summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.lint2
-rw-r--r--usr/src/Targetdirs4
-rw-r--r--usr/src/cmd/Makefile4
-rw-r--r--usr/src/cmd/idmap/Makefile48
-rw-r--r--usr/src/cmd/idmap/idmap/Makefile72
-rw-r--r--usr/src/cmd/idmap/idmap/idmap.c2109
-rw-r--r--usr/src/cmd/idmap/idmap/idmap_engine.c576
-rw-r--r--usr/src/cmd/idmap/idmap/idmap_engine.h68
-rw-r--r--usr/src/cmd/idmap/idmapd/Makefile109
-rw-r--r--usr/src/cmd/idmap/idmapd/adutils.c1493
-rw-r--r--usr/src/cmd/idmap/idmapd/adutils.h182
-rw-r--r--usr/src/cmd/idmap/idmapd/dbutils.c2665
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap.xml118
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap_config.c389
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap_config.h72
-rw-r--r--usr/src/cmd/idmap/idmapd/idmapd.c361
-rw-r--r--usr/src/cmd/idmap/idmapd/idmapd.h185
-rw-r--r--usr/src/cmd/idmap/idmapd/init.c151
-rw-r--r--usr/src/cmd/idmap/idmapd/mapfile-intf33
-rw-r--r--usr/src/cmd/idmap/idmapd/rpc_svc.c189
-rw-r--r--usr/src/cmd/idmap/idmapd/server.c726
-rw-r--r--usr/src/cmd/idmap/req.flg30
-rw-r--r--usr/src/cmd/rpcsvc/net_files/rpc10
-rw-r--r--usr/src/cmd/sqlite/Makefile69
-rw-r--r--usr/src/cmd/sqlite/shell.c (renamed from usr/src/cmd/svc/configd/sqlite/src/shell.c)0
-rw-r--r--usr/src/cmd/svc/configd/Makefile31
-rw-r--r--usr/src/cmd/svc/configd/backend.c17
-rw-r--r--usr/src/head/rpcsvc/idmap_prot.x160
-rw-r--r--usr/src/lib/Makefile6
-rw-r--r--usr/src/lib/libc/port/llib-lc1
-rw-r--r--usr/src/lib/libidmap/Makefile65
-rw-r--r--usr/src/lib/libidmap/Makefile.com64
-rw-r--r--usr/src/lib/libidmap/amd64/Makefile31
-rw-r--r--usr/src/lib/libidmap/common/idmap.h110
-rw-r--r--usr/src/lib/libidmap/common/idmap_api.c1689
-rw-r--r--usr/src/lib/libidmap/common/idmap_impl.h113
-rw-r--r--usr/src/lib/libidmap/common/idmap_priv.h143
-rw-r--r--usr/src/lib/libidmap/common/llib-lidmap31
-rw-r--r--usr/src/lib/libidmap/common/mapfile-vers74
-rw-r--r--usr/src/lib/libidmap/common/utils.c141
-rw-r--r--usr/src/lib/libidmap/i386/Makefile30
-rw-r--r--usr/src/lib/libidmap/sparc/Makefile30
-rw-r--r--usr/src/lib/libidmap/sparcv9/Makefile31
-rw-r--r--usr/src/lib/libsecdb/auth_attr.txt4
-rw-r--r--usr/src/lib/libsecdb/help/auths/IdmapRules.html40
-rw-r--r--usr/src/lib/libsecdb/help/auths/Makefile5
-rw-r--r--usr/src/lib/libsecdb/help/auths/SmfIdmapStates.html40
-rw-r--r--usr/src/lib/libsecdb/help/auths/SmfValueIdmap.html40
-rw-r--r--usr/src/lib/libsecdb/help/profiles/Makefile4
-rw-r--r--usr/src/lib/libsecdb/help/profiles/RtIdmapMngmnt.html40
-rw-r--r--usr/src/lib/libsecdb/help/profiles/RtIdmapNameRulesMngmnt.html41
-rw-r--r--usr/src/lib/libsecdb/prof_attr.txt2
-rw-r--r--usr/src/lib/libsqlite/Makefile64
-rw-r--r--usr/src/lib/libsqlite/Makefile.com (renamed from usr/src/cmd/svc/configd/sqlite/Makefile)55
-rw-r--r--usr/src/lib/libsqlite/i386/Makefile32
-rw-r--r--usr/src/lib/libsqlite/inc.flg (renamed from usr/src/cmd/svc/configd/sqlite/inc.flg)0
-rw-r--r--usr/src/lib/libsqlite/llib-lsqlite (renamed from usr/src/cmd/svc/configd/sqlite/llib-lsqlite)0
-rw-r--r--usr/src/lib/libsqlite/main.mk (renamed from usr/src/cmd/svc/configd/sqlite/main.mk)0
-rw-r--r--usr/src/lib/libsqlite/mapfile-sqlite (renamed from usr/src/cmd/svc/configd/sqlite/mapfile-sqlite)0
-rw-r--r--usr/src/lib/libsqlite/sparc/Makefile32
-rw-r--r--usr/src/lib/libsqlite/sqlite-misc.h (renamed from usr/src/cmd/svc/configd/sqlite/sqlite-misc.h)0
-rw-r--r--usr/src/lib/libsqlite/src/attach.c (renamed from usr/src/cmd/svc/configd/sqlite/src/attach.c)0
-rw-r--r--usr/src/lib/libsqlite/src/auth.c (renamed from usr/src/cmd/svc/configd/sqlite/src/auth.c)0
-rw-r--r--usr/src/lib/libsqlite/src/btree.c (renamed from usr/src/cmd/svc/configd/sqlite/src/btree.c)0
-rw-r--r--usr/src/lib/libsqlite/src/btree.h (renamed from usr/src/cmd/svc/configd/sqlite/src/btree.h)0
-rw-r--r--usr/src/lib/libsqlite/src/btree_rb.c (renamed from usr/src/cmd/svc/configd/sqlite/src/btree_rb.c)0
-rw-r--r--usr/src/lib/libsqlite/src/build.c (renamed from usr/src/cmd/svc/configd/sqlite/src/build.c)0
-rw-r--r--usr/src/lib/libsqlite/src/config.h (renamed from usr/src/cmd/svc/configd/sqlite/src/config.h)0
-rw-r--r--usr/src/lib/libsqlite/src/copy.c (renamed from usr/src/cmd/svc/configd/sqlite/src/copy.c)0
-rw-r--r--usr/src/lib/libsqlite/src/date.c (renamed from usr/src/cmd/svc/configd/sqlite/src/date.c)0
-rw-r--r--usr/src/lib/libsqlite/src/delete.c (renamed from usr/src/cmd/svc/configd/sqlite/src/delete.c)0
-rw-r--r--usr/src/lib/libsqlite/src/encode.c (renamed from usr/src/cmd/svc/configd/sqlite/src/encode.c)0
-rw-r--r--usr/src/lib/libsqlite/src/expr.c (renamed from usr/src/cmd/svc/configd/sqlite/src/expr.c)0
-rw-r--r--usr/src/lib/libsqlite/src/func.c (renamed from usr/src/cmd/svc/configd/sqlite/src/func.c)0
-rw-r--r--usr/src/lib/libsqlite/src/hash.c (renamed from usr/src/cmd/svc/configd/sqlite/src/hash.c)0
-rw-r--r--usr/src/lib/libsqlite/src/hash.h (renamed from usr/src/cmd/svc/configd/sqlite/src/hash.h)0
-rw-r--r--usr/src/lib/libsqlite/src/insert.c (renamed from usr/src/cmd/svc/configd/sqlite/src/insert.c)0
-rw-r--r--usr/src/lib/libsqlite/src/main.c (renamed from usr/src/cmd/svc/configd/sqlite/src/main.c)0
-rw-r--r--usr/src/lib/libsqlite/src/md5.c (renamed from usr/src/cmd/svc/configd/sqlite/src/md5.c)0
-rw-r--r--usr/src/lib/libsqlite/src/os.c (renamed from usr/src/cmd/svc/configd/sqlite/src/os.c)0
-rw-r--r--usr/src/lib/libsqlite/src/os.h (renamed from usr/src/cmd/svc/configd/sqlite/src/os.h)0
-rw-r--r--usr/src/lib/libsqlite/src/pager.c (renamed from usr/src/cmd/svc/configd/sqlite/src/pager.c)0
-rw-r--r--usr/src/lib/libsqlite/src/pager.h (renamed from usr/src/cmd/svc/configd/sqlite/src/pager.h)0
-rw-r--r--usr/src/lib/libsqlite/src/parse.y (renamed from usr/src/cmd/svc/configd/sqlite/src/parse.y)0
-rw-r--r--usr/src/lib/libsqlite/src/pragma.c (renamed from usr/src/cmd/svc/configd/sqlite/src/pragma.c)0
-rw-r--r--usr/src/lib/libsqlite/src/printf.c (renamed from usr/src/cmd/svc/configd/sqlite/src/printf.c)0
-rw-r--r--usr/src/lib/libsqlite/src/random.c (renamed from usr/src/cmd/svc/configd/sqlite/src/random.c)0
-rw-r--r--usr/src/lib/libsqlite/src/select.c (renamed from usr/src/cmd/svc/configd/sqlite/src/select.c)0
-rw-r--r--usr/src/lib/libsqlite/src/sqlite.h.in (renamed from usr/src/cmd/svc/configd/sqlite/src/sqlite.h.in)0
-rw-r--r--usr/src/lib/libsqlite/src/sqliteInt.h (renamed from usr/src/cmd/svc/configd/sqlite/src/sqliteInt.h)0
-rw-r--r--usr/src/lib/libsqlite/src/table.c (renamed from usr/src/cmd/svc/configd/sqlite/src/table.c)0
-rw-r--r--usr/src/lib/libsqlite/src/tclsqlite.c (renamed from usr/src/cmd/svc/configd/sqlite/src/tclsqlite.c)0
-rw-r--r--usr/src/lib/libsqlite/src/test1.c (renamed from usr/src/cmd/svc/configd/sqlite/src/test1.c)0
-rw-r--r--usr/src/lib/libsqlite/src/test2.c (renamed from usr/src/cmd/svc/configd/sqlite/src/test2.c)0
-rw-r--r--usr/src/lib/libsqlite/src/test3.c (renamed from usr/src/cmd/svc/configd/sqlite/src/test3.c)0
-rw-r--r--usr/src/lib/libsqlite/src/test4.c (renamed from usr/src/cmd/svc/configd/sqlite/src/test4.c)0
-rw-r--r--usr/src/lib/libsqlite/src/tokenize.c (renamed from usr/src/cmd/svc/configd/sqlite/src/tokenize.c)0
-rw-r--r--usr/src/lib/libsqlite/src/trigger.c (renamed from usr/src/cmd/svc/configd/sqlite/src/trigger.c)0
-rw-r--r--usr/src/lib/libsqlite/src/update.c (renamed from usr/src/cmd/svc/configd/sqlite/src/update.c)0
-rw-r--r--usr/src/lib/libsqlite/src/util.c (renamed from usr/src/cmd/svc/configd/sqlite/src/util.c)0
-rw-r--r--usr/src/lib/libsqlite/src/vacuum.c (renamed from usr/src/cmd/svc/configd/sqlite/src/vacuum.c)0
-rw-r--r--usr/src/lib/libsqlite/src/vdbe.c (renamed from usr/src/cmd/svc/configd/sqlite/src/vdbe.c)0
-rw-r--r--usr/src/lib/libsqlite/src/vdbe.h (renamed from usr/src/cmd/svc/configd/sqlite/src/vdbe.h)0
-rw-r--r--usr/src/lib/libsqlite/src/vdbeInt.h (renamed from usr/src/cmd/svc/configd/sqlite/src/vdbeInt.h)0
-rw-r--r--usr/src/lib/libsqlite/src/vdbeaux.c (renamed from usr/src/cmd/svc/configd/sqlite/src/vdbeaux.c)0
-rw-r--r--usr/src/lib/libsqlite/src/where.c (renamed from usr/src/cmd/svc/configd/sqlite/src/where.c)0
-rw-r--r--usr/src/lib/libsqlite/test/all.test (renamed from usr/src/cmd/svc/configd/sqlite/test/all.test)0
-rw-r--r--usr/src/lib/libsqlite/test/attach.test (renamed from usr/src/cmd/svc/configd/sqlite/test/attach.test)0
-rw-r--r--usr/src/lib/libsqlite/test/attach2.test (renamed from usr/src/cmd/svc/configd/sqlite/test/attach2.test)0
-rw-r--r--usr/src/lib/libsqlite/test/auth.test (renamed from usr/src/cmd/svc/configd/sqlite/test/auth.test)0
-rw-r--r--usr/src/lib/libsqlite/test/bigfile.test (renamed from usr/src/cmd/svc/configd/sqlite/test/bigfile.test)0
-rw-r--r--usr/src/lib/libsqlite/test/bigrow.test (renamed from usr/src/cmd/svc/configd/sqlite/test/bigrow.test)0
-rw-r--r--usr/src/lib/libsqlite/test/bind.test (renamed from usr/src/cmd/svc/configd/sqlite/test/bind.test)0
-rw-r--r--usr/src/lib/libsqlite/test/btree.test (renamed from usr/src/cmd/svc/configd/sqlite/test/btree.test)0
-rw-r--r--usr/src/lib/libsqlite/test/btree2.test (renamed from usr/src/cmd/svc/configd/sqlite/test/btree2.test)0
-rw-r--r--usr/src/lib/libsqlite/test/btree3.test (renamed from usr/src/cmd/svc/configd/sqlite/test/btree3.test)0
-rw-r--r--usr/src/lib/libsqlite/test/btree3rb.test (renamed from usr/src/cmd/svc/configd/sqlite/test/btree3rb.test)0
-rw-r--r--usr/src/lib/libsqlite/test/btree4.test (renamed from usr/src/cmd/svc/configd/sqlite/test/btree4.test)0
-rw-r--r--usr/src/lib/libsqlite/test/btree4rb.test (renamed from usr/src/cmd/svc/configd/sqlite/test/btree4rb.test)0
-rw-r--r--usr/src/lib/libsqlite/test/capi2.test (renamed from usr/src/cmd/svc/configd/sqlite/test/capi2.test)0
-rw-r--r--usr/src/lib/libsqlite/test/conflict.test (renamed from usr/src/cmd/svc/configd/sqlite/test/conflict.test)0
-rw-r--r--usr/src/lib/libsqlite/test/copy.test (renamed from usr/src/cmd/svc/configd/sqlite/test/copy.test)0
-rw-r--r--usr/src/lib/libsqlite/test/crashme2.off (renamed from usr/src/cmd/svc/configd/sqlite/test/crashme2.off)0
-rw-r--r--usr/src/lib/libsqlite/test/crashtest1.c (renamed from usr/src/cmd/svc/configd/sqlite/test/crashtest1.c)0
-rw-r--r--usr/src/lib/libsqlite/test/date.test (renamed from usr/src/cmd/svc/configd/sqlite/test/date.test)0
-rw-r--r--usr/src/lib/libsqlite/test/delete.test (renamed from usr/src/cmd/svc/configd/sqlite/test/delete.test)0
-rw-r--r--usr/src/lib/libsqlite/test/expr.test (renamed from usr/src/cmd/svc/configd/sqlite/test/expr.test)0
-rw-r--r--usr/src/lib/libsqlite/test/fkey1.test (renamed from usr/src/cmd/svc/configd/sqlite/test/fkey1.test)0
-rw-r--r--usr/src/lib/libsqlite/test/format3.test (renamed from usr/src/cmd/svc/configd/sqlite/test/format3.test)0
-rw-r--r--usr/src/lib/libsqlite/test/func.test (renamed from usr/src/cmd/svc/configd/sqlite/test/func.test)0
-rw-r--r--usr/src/lib/libsqlite/test/hook.test (renamed from usr/src/cmd/svc/configd/sqlite/test/hook.test)0
-rw-r--r--usr/src/lib/libsqlite/test/in.test (renamed from usr/src/cmd/svc/configd/sqlite/test/in.test)0
-rw-r--r--usr/src/lib/libsqlite/test/index.test (renamed from usr/src/cmd/svc/configd/sqlite/test/index.test)0
-rw-r--r--usr/src/lib/libsqlite/test/insert.test (renamed from usr/src/cmd/svc/configd/sqlite/test/insert.test)0
-rw-r--r--usr/src/lib/libsqlite/test/insert2.test (renamed from usr/src/cmd/svc/configd/sqlite/test/insert2.test)0
-rw-r--r--usr/src/lib/libsqlite/test/interrupt.test (renamed from usr/src/cmd/svc/configd/sqlite/test/interrupt.test)0
-rw-r--r--usr/src/lib/libsqlite/test/intpkey.test (renamed from usr/src/cmd/svc/configd/sqlite/test/intpkey.test)0
-rw-r--r--usr/src/lib/libsqlite/test/ioerr.test (renamed from usr/src/cmd/svc/configd/sqlite/test/ioerr.test)0
-rw-r--r--usr/src/lib/libsqlite/test/join.test (renamed from usr/src/cmd/svc/configd/sqlite/test/join.test)0
-rw-r--r--usr/src/lib/libsqlite/test/join2.test (renamed from usr/src/cmd/svc/configd/sqlite/test/join2.test)0
-rw-r--r--usr/src/lib/libsqlite/test/join3_28.test (renamed from usr/src/cmd/svc/configd/sqlite/test/join3_28.test)0
-rw-r--r--usr/src/lib/libsqlite/test/join4_28.test (renamed from usr/src/cmd/svc/configd/sqlite/test/join4_28.test)0
-rw-r--r--usr/src/lib/libsqlite/test/lastinsert.test (renamed from usr/src/cmd/svc/configd/sqlite/test/lastinsert.test)0
-rw-r--r--usr/src/lib/libsqlite/test/laststmtchanges.test (renamed from usr/src/cmd/svc/configd/sqlite/test/laststmtchanges.test)0
-rw-r--r--usr/src/lib/libsqlite/test/limit.test (renamed from usr/src/cmd/svc/configd/sqlite/test/limit.test)0
-rw-r--r--usr/src/lib/libsqlite/test/lock.test (renamed from usr/src/cmd/svc/configd/sqlite/test/lock.test)0
-rw-r--r--usr/src/lib/libsqlite/test/main.test (renamed from usr/src/cmd/svc/configd/sqlite/test/main.test)0
-rw-r--r--usr/src/lib/libsqlite/test/malloc.test (renamed from usr/src/cmd/svc/configd/sqlite/test/malloc.test)0
-rw-r--r--usr/src/lib/libsqlite/test/memdb.test (renamed from usr/src/cmd/svc/configd/sqlite/test/memdb.test)0
-rw-r--r--usr/src/lib/libsqlite/test/memleak.test (renamed from usr/src/cmd/svc/configd/sqlite/test/memleak.test)0
-rw-r--r--usr/src/lib/libsqlite/test/minmax.test (renamed from usr/src/cmd/svc/configd/sqlite/test/minmax.test)0
-rw-r--r--usr/src/lib/libsqlite/test/misc1.test (renamed from usr/src/cmd/svc/configd/sqlite/test/misc1.test)0
-rw-r--r--usr/src/lib/libsqlite/test/misc2.test (renamed from usr/src/cmd/svc/configd/sqlite/test/misc2.test)0
-rw-r--r--usr/src/lib/libsqlite/test/misc3.test (renamed from usr/src/cmd/svc/configd/sqlite/test/misc3.test)0
-rw-r--r--usr/src/lib/libsqlite/test/misuse.test (renamed from usr/src/cmd/svc/configd/sqlite/test/misuse.test)0
-rw-r--r--usr/src/lib/libsqlite/test/notnull.test (renamed from usr/src/cmd/svc/configd/sqlite/test/notnull.test)0
-rw-r--r--usr/src/lib/libsqlite/test/null.test (renamed from usr/src/cmd/svc/configd/sqlite/test/null.test)0
-rw-r--r--usr/src/lib/libsqlite/test/pager.test (renamed from usr/src/cmd/svc/configd/sqlite/test/pager.test)0
-rw-r--r--usr/src/lib/libsqlite/test/pragma.test (renamed from usr/src/cmd/svc/configd/sqlite/test/pragma.test)0
-rw-r--r--usr/src/lib/libsqlite/test/printf.test (renamed from usr/src/cmd/svc/configd/sqlite/test/printf.test)0
-rw-r--r--usr/src/lib/libsqlite/test/progress.test (renamed from usr/src/cmd/svc/configd/sqlite/test/progress.test)0
-rw-r--r--usr/src/lib/libsqlite/test/quick.test (renamed from usr/src/cmd/svc/configd/sqlite/test/quick.test)0
-rw-r--r--usr/src/lib/libsqlite/test/quote.test (renamed from usr/src/cmd/svc/configd/sqlite/test/quote.test)0
-rw-r--r--usr/src/lib/libsqlite/test/rowid.test (renamed from usr/src/cmd/svc/configd/sqlite/test/rowid.test)0
-rw-r--r--usr/src/lib/libsqlite/test/select1.test (renamed from usr/src/cmd/svc/configd/sqlite/test/select1.test)0
-rw-r--r--usr/src/lib/libsqlite/test/select2.test (renamed from usr/src/cmd/svc/configd/sqlite/test/select2.test)0
-rw-r--r--usr/src/lib/libsqlite/test/select3.test (renamed from usr/src/cmd/svc/configd/sqlite/test/select3.test)0
-rw-r--r--usr/src/lib/libsqlite/test/select4.test (renamed from usr/src/cmd/svc/configd/sqlite/test/select4.test)0
-rw-r--r--usr/src/lib/libsqlite/test/select5.test (renamed from usr/src/cmd/svc/configd/sqlite/test/select5.test)0
-rw-r--r--usr/src/lib/libsqlite/test/select6.test (renamed from usr/src/cmd/svc/configd/sqlite/test/select6.test)0
-rw-r--r--usr/src/lib/libsqlite/test/sort.test (renamed from usr/src/cmd/svc/configd/sqlite/test/sort.test)0
-rw-r--r--usr/src/lib/libsqlite/test/subselect.test (renamed from usr/src/cmd/svc/configd/sqlite/test/subselect.test)0
-rw-r--r--usr/src/lib/libsqlite/test/table.test (renamed from usr/src/cmd/svc/configd/sqlite/test/table.test)0
-rw-r--r--usr/src/lib/libsqlite/test/tableapi.test (renamed from usr/src/cmd/svc/configd/sqlite/test/tableapi.test)0
-rw-r--r--usr/src/lib/libsqlite/test/tclsqlite.test (renamed from usr/src/cmd/svc/configd/sqlite/test/tclsqlite.test)0
-rw-r--r--usr/src/lib/libsqlite/test/temptable.test (renamed from usr/src/cmd/svc/configd/sqlite/test/temptable.test)0
-rw-r--r--usr/src/lib/libsqlite/test/tester.tcl (renamed from usr/src/cmd/svc/configd/sqlite/test/tester.tcl)0
-rw-r--r--usr/src/lib/libsqlite/test/thread1.test (renamed from usr/src/cmd/svc/configd/sqlite/test/thread1.test)0
-rw-r--r--usr/src/lib/libsqlite/test/threadtest1.c (renamed from usr/src/cmd/svc/configd/sqlite/test/threadtest1.c)0
-rw-r--r--usr/src/lib/libsqlite/test/threadtest2.c (renamed from usr/src/cmd/svc/configd/sqlite/test/threadtest2.c)0
-rw-r--r--usr/src/lib/libsqlite/test/trans.test (renamed from usr/src/cmd/svc/configd/sqlite/test/trans.test)0
-rw-r--r--usr/src/lib/libsqlite/test/trigger1.test (renamed from usr/src/cmd/svc/configd/sqlite/test/trigger1.test)0
-rw-r--r--usr/src/lib/libsqlite/test/trigger2.test (renamed from usr/src/cmd/svc/configd/sqlite/test/trigger2.test)0
-rw-r--r--usr/src/lib/libsqlite/test/trigger3.test (renamed from usr/src/cmd/svc/configd/sqlite/test/trigger3.test)0
-rw-r--r--usr/src/lib/libsqlite/test/trigger4.test (renamed from usr/src/cmd/svc/configd/sqlite/test/trigger4.test)0
-rw-r--r--usr/src/lib/libsqlite/test/unique.test (renamed from usr/src/cmd/svc/configd/sqlite/test/unique.test)0
-rw-r--r--usr/src/lib/libsqlite/test/update.test (renamed from usr/src/cmd/svc/configd/sqlite/test/update.test)0
-rw-r--r--usr/src/lib/libsqlite/test/vacuum.test (renamed from usr/src/cmd/svc/configd/sqlite/test/vacuum.test)0
-rw-r--r--usr/src/lib/libsqlite/test/version.test (renamed from usr/src/cmd/svc/configd/sqlite/test/version.test)0
-rw-r--r--usr/src/lib/libsqlite/test/view.test (renamed from usr/src/cmd/svc/configd/sqlite/test/view.test)0
-rw-r--r--usr/src/lib/libsqlite/test/where.test (renamed from usr/src/cmd/svc/configd/sqlite/test/where.test)0
-rw-r--r--usr/src/lib/libsqlite/tool/diffdb.c (renamed from usr/src/cmd/svc/configd/sqlite/tool/diffdb.c)0
-rw-r--r--usr/src/lib/libsqlite/tool/lemon.c (renamed from usr/src/cmd/svc/configd/sqlite/tool/lemon.c)0
-rw-r--r--usr/src/lib/libsqlite/tool/lempar.c (renamed from usr/src/cmd/svc/configd/sqlite/tool/lempar.c)0
-rw-r--r--usr/src/lib/libsqlite/tool/memleak.awk (renamed from usr/src/cmd/svc/configd/sqlite/tool/memleak.awk)0
-rw-r--r--usr/src/lib/libsqlite/tool/memleak2.awk (renamed from usr/src/cmd/svc/configd/sqlite/tool/memleak2.awk)0
-rw-r--r--usr/src/lib/libsqlite/tool/mkopts.tcl (renamed from usr/src/cmd/svc/configd/sqlite/tool/mkopts.tcl)0
-rw-r--r--usr/src/lib/libsqlite/tool/opcodeDoc.awk (renamed from usr/src/cmd/svc/configd/sqlite/tool/opcodeDoc.awk)0
-rw-r--r--usr/src/lib/libsqlite/tool/report1.txt (renamed from usr/src/cmd/svc/configd/sqlite/tool/report1.txt)0
-rw-r--r--usr/src/lib/libsqlite/tool/showdb.c (renamed from usr/src/cmd/svc/configd/sqlite/tool/showdb.c)0
-rw-r--r--usr/src/lib/libsqlite/tool/showjournal.c (renamed from usr/src/cmd/svc/configd/sqlite/tool/showjournal.c)0
-rw-r--r--usr/src/lib/libsqlite/tool/space_used.tcl (renamed from usr/src/cmd/svc/configd/sqlite/tool/space_used.tcl)0
-rw-r--r--usr/src/lib/libsqlite/tool/spaceanal.tcl (renamed from usr/src/cmd/svc/configd/sqlite/tool/spaceanal.tcl)0
-rw-r--r--usr/src/lib/libsqlite/tool/speedtest.tcl (renamed from usr/src/cmd/svc/configd/sqlite/tool/speedtest.tcl)0
-rw-r--r--usr/src/lib/libsqlite/tool/speedtest2.tcl (renamed from usr/src/cmd/svc/configd/sqlite/tool/speedtest2.tcl)0
-rw-r--r--usr/src/pkgdefs/SUNW0on/prototype_com5
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_i3862
-rw-r--r--usr/src/pkgdefs/SUNWckr/prototype_sparc1
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_com1
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_i3861
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_sparc1
-rw-r--r--usr/src/pkgdefs/SUNWcsr/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWcsu/prototype_com7
-rw-r--r--usr/src/pkgdefs/etc/exception_list_i38621
-rw-r--r--usr/src/pkgdefs/etc/exception_list_sparc21
-rw-r--r--usr/src/tools/abi/etc/exceptions3
-rw-r--r--usr/src/tools/findunref/exception_list3
-rw-r--r--usr/src/uts/Makefile3
-rw-r--r--usr/src/uts/common/Makefile.files5
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rwxr-xr-xusr/src/uts/common/idmap/Makefile61
-rw-r--r--usr/src/uts/common/idmap/idmap_cache.c474
-rw-r--r--usr/src/uts/common/idmap/idmap_kapi.c1318
-rw-r--r--usr/src/uts/common/idmap/idmap_mod.c103
-rw-r--r--usr/src/uts/common/idmap/kidmap_priv.h99
-rw-r--r--usr/src/uts/common/os/cred.c13
-rw-r--r--usr/src/uts/common/os/sid.c32
-rw-r--r--usr/src/uts/common/sys/Makefile2
-rw-r--r--usr/src/uts/common/sys/idmap.h74
-rw-r--r--usr/src/uts/common/sys/kidmap.h158
-rw-r--r--usr/src/uts/common/sys/sid.h22
-rw-r--r--usr/src/uts/common/syscall/gid.c6
-rw-r--r--usr/src/uts/common/syscall/sidsys.c232
-rw-r--r--usr/src/uts/common/syscall/uid.c6
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared1
-rw-r--r--usr/src/uts/intel/ia32/ml/modstubs.s25
-rwxr-xr-xusr/src/uts/intel/idmap/Makefile97
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared1
-rwxr-xr-xusr/src/uts/sparc/idmap/Makefile98
-rw-r--r--usr/src/uts/sparc/ml/modstubs.s25
240 files changed, 15446 insertions, 315 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index f0e9bcadec..6e8304e06c 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -152,6 +152,7 @@ COMMON_SUBDIRS = \
cmd/head \
cmd/hostid \
cmd/hostname \
+ cmd/idmap \
cmd/init \
cmd/intrstat \
cmd/ipcrm \
@@ -329,6 +330,7 @@ COMMON_SUBDIRS = \
lib/libexacct \
lib/libgen \
lib/libgss \
+ lib/libidmap \
lib/libinetcfg \
lib/libinetsvc \
lib/libinetutil \
diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs
index 186534afac..919938be80 100644
--- a/usr/src/Targetdirs
+++ b/usr/src/Targetdirs
@@ -423,6 +423,7 @@ OTHERS= \
/var/adm/exacct \
/var/adm/log \
/var/adm/sa \
+ /var/idmap \
/var/mail \
/var/spool/lp \
/var/tmp
@@ -518,6 +519,9 @@ $(SYM.ROOT.SYS:%=$(ROOT)%):= GROUP= sys
$(ROOT)/var/adm \
$(ROOT)/var/adm/sa := DIRMODE= 775
+$(ROOT)/var/idmap := OWNER= daemon
+$(ROOT)/var/idmap := GROUP= daemon
+
$(ROOT)/dev/term:= GROUP= root
$(UUCP.UUCP:%=$(ROOT)%):= OWNER= uucp
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index 1d741cb234..1688589ec5 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -191,6 +191,7 @@ COMMON_SUBDIRS= \
hostname \
hwdata \
id \
+ idmap \
infocmp \
init \
initpkg \
@@ -349,6 +350,7 @@ COMMON_SUBDIRS= \
spell \
spline \
split \
+ sqlite \
srchtxt \
ssh \
stat \
@@ -565,6 +567,7 @@ MSGSUBDIRS= \
head \
hostname \
id \
+ idmap \
isaexec \
iscsi \
join \
@@ -820,6 +823,7 @@ MANIFEST_SUBDIRS= \
fs.d/cachefs \
fs.d/nfs/svc \
gss/gssd \
+ idmap/idmapd \
krb5/kadmin/server \
krb5/krb5kdc \
krb5/kwarn \
diff --git a/usr/src/cmd/idmap/Makefile b/usr/src/cmd/idmap/Makefile
new file mode 100644
index 0000000000..3242cdfa22
--- /dev/null
+++ b/usr/src/cmd/idmap/Makefile
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Makefile for native identity mapping service
+#
+
+SUBDIR_CMD= idmap
+SUBDIR_DAEMON= idmapd
+SUBDIRS= $(SUBDIR_CMD) $(SUBDIR_DAEMON)
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+_msg := TARGET = _msg
+
+.KEEP_STATE:
+
+all install lint clean clobber _msg: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/idmap/idmap/Makefile b/usr/src/cmd/idmap/idmap/Makefile
new file mode 100644
index 0000000000..fef261b9e9
--- /dev/null
+++ b/usr/src/cmd/idmap/idmap/Makefile
@@ -0,0 +1,72 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG = idmap
+CLIENTOBJS = idmap.o idmap_engine.o
+# idmap_clnt.o
+CLIENTSRCS = $(CLIENTOBJS:%.o=%.c)
+POFILES = $(CLIENTOBJS:.o=.po)
+OBJS = $(CLIENTOBJS)
+SRCS = $(CLIENTSRCS)
+IDMAP_PROT_DIR = $(SRC)/head/rpcsvc
+
+include ../../Makefile.cmd
+
+POFILE = $(PROG)_all.po
+LDLIBS += -lidmap
+FILEMODE = 0555
+GROUP = bin
+
+INCS += -I. -I../../../lib/libidmap/common -I$(IDMAP_PROT_DIR)
+
+$(OBJS) := CPPFLAGS += $(INCS) -D_REENTRANT
+$(POFILE) := CPPFLAGS += $(INCS)
+
+lint_SRCS := CPPFLAGS += $(INCS)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -g -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ cat $(POFILES) > $@
+
+install: all $(ROOTUSRSBINPROG)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_SRCS
+
+include ../../Makefile.targ
+
+
diff --git a/usr/src/cmd/idmap/idmap/idmap.c b/usr/src/cmd/idmap/idmap/idmap.c
new file mode 100644
index 0000000000..772e7eff8c
--- /dev/null
+++ b/usr/src/cmd/idmap/idmap/idmap.c
@@ -0,0 +1,2109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <strings.h>
+#include "idmap_engine.h"
+#include "idmap_priv.h"
+
+/* Initialization values for pids/rids: */
+
+#define UNDEFINED_UID (uid_t)-1
+#define UNDEFINED_GID (gid_t)-1
+#define UNDEFINED_RID (idmap_rid_t)-1;
+
+/* is_user values */
+
+#define I_YES 1
+#define I_NO 0
+#define I_UNKNOWN -1
+
+/* Directions */
+
+#define DIR_W2U 1
+#define DIR_U2W 2
+#define DIR_BI 0
+#define DIR_UNKNOWN -1
+
+/*
+ * used in do_show for the type of argument, which can be winname,
+ * unixname, uid, gid, sid or not given at all:
+ */
+
+#define TYPE_SID 0x010 /* sid */
+#define TYPE_WN 0x110 /* winname */
+#define TYPE_UID 0x001 /* uid */
+#define TYPE_GID 0x002 /* gid */
+#define TYPE_PID 0x000 /* pid */
+#define TYPE_UN 0x100 /* unixname */
+
+#define IS_WIN 0x010 /* mask for the windows types */
+#define IS_NAME 0x100 /* mask for string name types */
+#define IS_GROUP 0x002 /* mask for, well, TYPE_GID */
+
+
+/* Identity type strings */
+
+#define ID_WINNAME "winname"
+#define ID_UNIXNAME "unixname"
+#define ID_SID "sid"
+#define ID_UID "uid"
+#define ID_GID "gid"
+
+/* Flags */
+
+#define g_FLAG 'g'
+#define u_FLAG 'u'
+#define f_FLAG 'f'
+#define t_FLAG 't'
+#define d_FLAG 'd'
+#define F_FLAG 'F'
+#define a_FLAG 'a'
+#define n_FLAG 'n'
+#define c_FLAG 'c'
+
+
+/* used in the function do_import */
+#define MAX_INPUT_LINE_SZ 2047
+
+
+typedef struct {
+ int is_user;
+ int direction;
+ boolean_t is_nt4;
+ char *unixname;
+ char *winname;
+ char *windomain;
+ char *sidprefix;
+ idmap_rid_t rid;
+ uid_t pid;
+} name_mapping_t;
+
+/*
+ * Formats of the output:
+ *
+ * Idmap reads/prints mappings in several formats: ordinary mappings,
+ * name mappings in Samba username map format (smbusers), Netapp
+ * usermap.cfg.
+ *
+ * DEFAULT_FORMAT are in fact the idmap subcommands suitable for
+ * piping to idmap standart input. For example
+ * add -u -d winname:bob@foo.com unixname:fred
+ * add -u -d winname:bob2bar.com unixname:fred
+ *
+ * SMBUSERS is the format of Samba username map (smbusers). For full
+ * documentation, search for "username map" in smb.conf manpage.
+ * The format is for example
+ * fred = bob@foo.com bob2@bar.com
+ *
+ * USERMAP_CFG is the format of Netapp usermap.cfg file. Search
+ * http://www.netapp.com/ for more documentation. IP qualifiers are not
+ * supported.
+ * The format is for example
+ * bob@foo.com => fred
+ * "Bob With Spaces"@bar.com => fred #comment
+ *
+ * The previous formats were for name rules. MAPPING_NAME and
+ * MAPPING_ID are for the actual mappings, as seen in show/dump
+ * commands. MAPPING_NAME prefers the string names of the user over
+ * their numerical identificators. MAPPING_ID prints just the
+ * identificators.
+ * Example of the MAPPING_NAME:
+ * winname:bob@foo.com -> unixname:fred
+ *
+ * Example of the MAPPING_ID:
+ * sid:S-1-2-3-4 -> uid:5678
+ */
+
+typedef enum {
+ UNDEFINED_FORMAT = -1,
+ DEFAULT_FORMAT = 0,
+ MAPPING_ID,
+ MAPPING_NAME,
+ USERMAP_CFG,
+ SMBUSERS
+} format_t;
+
+/* Gives the format to use. Set in print_mapping_init */
+static format_t pnm_format;
+
+/* The file for print_mapping_init output. Mostly just stdout. */
+static FILE *pnm_file;
+
+/* In smbusers format, more unixnames can be aggregated to one line. */
+static char *pnm_last_unixname;
+
+/*
+ * idmap_api batch related variables:
+ *
+ * idmap can operate in two modes. It the batch mode, the idmap_api
+ * batch is commited at the end of a batch of several
+ * commands. At the end of input file, typically. This mode is used
+ * for processing input from a file.
+ * In the non-batch mode, each command is commited immediately. This
+ * mode is used for tty input.
+ */
+
+/* Are we in the batch mode? */
+static int batch_mode = 0;
+
+/* Handles for idmap_api batch */
+static idmap_handle_t *handle = NULL;
+static idmap_udt_handle_t *udt = NULL;
+
+/* Do we need to commit the udt batch at the end? */
+static int udt_used;
+
+/* Command handlers */
+
+static int do_show_mapping(flag_t *f, int argc, char **argv);
+static int do_dump(flag_t *f, int argc, char **argv);
+static int do_import(flag_t *f, int argc, char **argv);
+static int do_list_name_mappings(flag_t *f, int argc, char **argv);
+static int do_add_name_mapping(flag_t *f, int argc, char **argv);
+static int do_remove_name_mapping(flag_t *f, int argc, char **argv);
+static int do_exit(flag_t *f, int argc, char **argv);
+static int do_export(flag_t *f, int argc, char **argv);
+static int do_help(flag_t *f, int argc, char **argv);
+
+/* Command names and their hanlers to be passed to idmap_engine */
+
+static cmd_ops_t commands[] = {
+ {
+ "show",
+ "c(create)",
+ do_show_mapping
+ },
+ {
+ "dump",
+ "n(names)g(group)u(user)",
+ do_dump
+ },
+ {
+ "import",
+ "F(flush)f:(file)",
+ do_import
+ },
+ {
+ "export",
+ "f:(file)",
+ do_export
+ },
+ {
+ "list",
+ "g(group)u(user)",
+ do_list_name_mappings
+ },
+ {
+ "add",
+ "g(group)u(user)d(directional)",
+ do_add_name_mapping
+ },
+ {
+ "remove",
+ "a(all)u(user)g(group)t(to)f(from)d(directional)",
+ do_remove_name_mapping
+ },
+ {
+ "exit",
+ "",
+ do_exit
+ },
+ {
+ "help",
+ "",
+ do_help
+ }
+};
+
+/* Print help message */
+static void
+help() {
+ (void) fprintf(stderr,
+ "idmap\n"
+ "idmap -f command-file\n"
+ "idmap show [-c] identity [targettype]\n"
+ "idmap dump [-u|-g] [-n]\n"
+ "idmap add -u|-g [-d] name1 name2\n"
+ "idmap remove -u|-g -a\n"
+ "idmap remove -u|-g name\n"
+ "idmap remove -u|-g [-d] name1 name2\n"
+ "idmap list [-u|-g]\n"
+ "idmap import [-F] [-f file] format\n"
+ "idmap export [-f file] format\n"
+ "idmap help\n");
+}
+
+/* The handler for the "help" command. */
+static int
+/* LINTED E_FUNC_ARG_UNUSED */
+do_help(flag_t *f, int argc, char **argv)
+{
+ help();
+ return (0);
+}
+
+/* Initialization of the idmap api batch */
+static int
+init_batch() {
+ idmap_stat stat;
+
+ stat = idmap_init(&handle);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Connection not established (%s)\n"),
+ idmap_stat2string(NULL, stat));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Initialization common to all commands */
+static int
+init_command() {
+ if (batch_mode)
+ return (0);
+
+ return (init_batch());
+}
+
+/* Finalization common to all commands */
+static void
+fini_command() {
+ if (batch_mode)
+ return;
+ (void) idmap_fini(handle);
+ handle = NULL;
+}
+
+/* Initialization of the commands which perform write operations */
+static int
+init_udt_batch() {
+ idmap_stat stat;
+
+ if (init_batch())
+ return (-1);
+
+ stat = idmap_udt_create(handle, &udt);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Error initiating transaction (%s)"),
+ idmap_stat2string(handle, stat));
+ return (-1);
+ }
+ return (0);
+}
+
+
+/* Finalization of the write commands */
+static int
+init_udt_command() {
+ udt_used = 1;
+ if (batch_mode)
+ return (0);
+
+ return (init_udt_batch());
+}
+
+
+/* If everythings is OK, send the udt batch to idmapd */
+static void
+fini_udt_command(int ok) {
+ idmap_stat stat;
+
+ if (batch_mode)
+ return;
+ if (udt == NULL)
+ return;
+
+ if (ok && udt_used) {
+ stat = idmap_udt_commit(udt);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Error commiting transaction (%s)\n"),
+ idmap_stat2string(handle, stat));
+ }
+ }
+
+ idmap_udt_destroy(udt);
+ udt = NULL;
+ udt_used = 0;
+ fini_command();
+}
+
+
+/* Convert numeric expression of the direction to it's string form */
+static char *
+direction2string(int direction) {
+ switch (direction) {
+ case DIR_BI:
+ return ("==");
+ case DIR_W2U:
+ return ("=>");
+ case DIR_U2W:
+ return ("<=");
+ default:
+ (void) fprintf(stderr, gettext("Internal error.\n"));
+ return ("");
+ }
+ /* never reached */
+}
+
+/* Do we need quotation marks around winname in the USERMAP_CFG format? */
+static int
+needs_protection(char *what) {
+ if (strchr(what, ' ') != NULL)
+ return (1);
+
+ if (strchr(what, '\t') != NULL)
+ return (1);
+
+ if (strchr(what, '#') != NULL)
+ return (1);
+
+ return (0);
+}
+
+/* Protect all shell-special characters by '\\' */
+static int
+shell_app(char **res, char *string) {
+ size_t res_len = 0;
+ size_t res_size = 24;
+ int i;
+ char c;
+
+ *res = (char *)malloc(res_size * sizeof (char));
+ if (*res == NULL) {
+ (void) fprintf(stderr, gettext("Not enough memory.\n"));
+ return (-1);
+ }
+
+ for (i = 0; string[i] != '\0'; i++) {
+ c = string[i];
+
+ if (strchr("\"\\ \t#$", c) != NULL)
+ (*res)[res_len++] = '\\';
+ (*res)[res_len++] = c;
+
+ if (res_size - 1 <= res_len) {
+ res_size *= 2;
+ *res = (char *)realloc(*res, res_size * sizeof (char));
+ if (*res == NULL) {
+ (void) fprintf(stderr,
+ gettext("Not enough memory.\n"));
+ return (-1);
+ }
+ }
+ }
+
+ (*res)[res_len++] = '\0';
+ return (0);
+}
+
+/* Assemble string form sid */
+static char *
+sid_format(char *sidprefix, idmap_rid_t rid) {
+ char *to;
+ size_t len;
+
+ /* 'sid:' + sidprefix + '-' + rid + '\0' */
+ len = strlen(sidprefix) + 6 + 3 * sizeof (rid);
+ to = (char *)malloc(len * sizeof (char));
+ if (to == NULL)
+ return (NULL);
+
+ (void) snprintf(to, len, "sid:%s-%u", sidprefix, rid);
+ return (to);
+}
+
+/* Assemble string form uid or gid */
+static char *
+pid_format(uid_t from, int is_user) {
+ char *to;
+ size_t len;
+
+ /* ID_UID ":" + uid + '\0' */
+ len = 5 + 3 * sizeof (uid_t);
+ to = (char *)malloc(len * sizeof (char));
+ if (to == NULL)
+ return (NULL);
+
+ (void) snprintf(to, 16, "%s:%u", is_user ? ID_UID : ID_GID, from);
+ return (to);
+}
+
+/* Assemble winname, e.g. "winname:bob@foo.sun.com", from name_mapping_t */
+static int
+nm2winqn(name_mapping_t *nm, char **winqn) {
+ char *out;
+ size_t length = 0;
+ int is_domain = 1;
+
+ /* Sometimes there are no text names. Return a sid, then. */
+ if (nm->winname == NULL) {
+ if (nm->sidprefix == NULL)
+ return (-1);
+
+ *winqn = sid_format(nm->sidprefix, nm->rid);
+ return (0);
+ }
+
+ length = strlen(ID_WINNAME ":") + strlen(nm->winname);
+
+ /* Windomain is not mandatory: */
+ if (nm->windomain == NULL ||
+ *nm->winname == '\0' ||
+ strcmp(nm->winname, "\"\"") == 0)
+ is_domain = 0;
+ else
+ length += strlen(nm->windomain) + 1;
+
+ out = (char *)malloc((length + 1) * sizeof (char));
+ if (out == NULL) {
+ (void) fprintf(stderr,
+ gettext("Not enough memory.\n"));
+ return (-1);
+ }
+
+ (void) strcpy(out, ID_WINNAME ":");
+
+ if (!is_domain)
+ (void) strcat(out, nm->winname);
+ else if (nm->is_nt4) {
+ (void) strcat(out, nm->windomain);
+ (void) strcat(out, "\\");
+ (void) strcat(out, nm->winname);
+ } else {
+ (void) strcat(out, nm->winname);
+ (void) strcat(out, "@");
+ (void) strcat(out, nm->windomain);
+ }
+
+ *winqn = out;
+ return (0);
+}
+
+/* Assemble a text unixname, e.g. unixname:fred */
+static int
+nm2unixname(name_mapping_t *nm, char **unixname) {
+ size_t length = 0;
+ char *out;
+ char *it;
+
+ /* Sometimes there is no name, just pid: */
+ if (nm->unixname == NULL) {
+ if (nm->pid == UNDEFINED_UID)
+ return (-1);
+
+ *unixname = pid_format(nm->pid, nm->is_user);
+ return (0);
+ }
+
+ if (shell_app(&it, nm->unixname))
+ return (-1);
+
+ length = strlen(ID_UNIXNAME ":") + strlen(it);
+
+ out = (char *)malloc((length + 1) * sizeof (char));
+ if (out == NULL) {
+ (void) fprintf(stderr,
+ gettext("Not enough memory.\n"));
+ free(it);
+ return (-1);
+ }
+
+ (void) strcpy(out, ID_UNIXNAME ":");
+ (void) strcat(out, it);
+ free(it);
+
+ *unixname = out;
+ return (0);
+}
+
+/* Initialize print_mapping variables. Must be called before print_mapping */
+static int
+print_mapping_init(format_t f, FILE *fi) {
+ pnm_format = f;
+ pnm_file = fi;
+
+ switch (pnm_format) {
+ case SMBUSERS:
+ pnm_last_unixname = NULL;
+ break;
+ default:
+ ;
+ }
+
+ return (0);
+}
+
+/* Finalize print_mapping. */
+static int
+print_mapping_fini() {
+ switch (pnm_format) {
+ case SMBUSERS:
+ if (pnm_last_unixname != NULL) {
+ (void) fprintf(pnm_file, "\n");
+ free(pnm_last_unixname);
+ }
+ break;
+ default:
+ ;
+ }
+
+ pnm_file = stderr;
+ pnm_format = UNDEFINED_FORMAT;
+
+ return (0);
+}
+
+/*
+ * This prints both name rules and ordinary mappings, based on the pnm_format
+ * set in print_mapping_init().
+ */
+
+static int
+print_mapping(name_mapping_t *nm)
+{
+ char *dirstring;
+ char *winname_qm, *windomain_qm, *unixname_qm;
+ char type;
+ char *winname = NULL;
+ char *winname1 = NULL;
+ char *unixname = NULL;
+ FILE *f = pnm_file;
+
+
+ switch (pnm_format) {
+ case MAPPING_NAME:
+ if (nm2winqn(nm, &winname) < 0)
+ return (-1);
+ if (nm2unixname(nm, &unixname) < 0) {
+ free(winname);
+ return (-1);
+ }
+ /* LINTED E_CASE_FALLTHRU */
+ case MAPPING_ID:
+ if (pnm_format == MAPPING_ID) {
+ if (nm->sidprefix == NULL) {
+ (void) fprintf(stderr,
+ gettext("SID not given.\n"));
+ return (-1);
+ }
+ winname = sid_format(nm->sidprefix, nm->rid);
+ if (winname == NULL)
+ return (-1);
+ unixname = pid_format(nm->pid, nm->is_user);
+ if (unixname == NULL) {
+ free(winname);
+ return (-1);
+ }
+ }
+
+ dirstring = direction2string(nm->direction);
+
+ (void) fprintf(f, "%s\t%s\t%s\n", winname, dirstring,
+ unixname);
+
+ free(winname);
+ free(unixname);
+ break;
+ case SMBUSERS:
+ if (!nm->is_user) {
+ (void) fprintf(stderr,
+ gettext("Group rule: "));
+ f = stderr;
+ } else if (nm->direction == DIR_U2W) {
+ (void) fprintf(stderr,
+ gettext("Opposite direction of the mapping: "));
+ f = stderr;
+ }
+ if (shell_app(&winname, nm->winname))
+ return (-1);
+
+ if (pnm_file != f) {
+ (void) fprintf(f, "%s = %s\n", nm->unixname, winname);
+ } else if (pnm_last_unixname != NULL &&
+ strcmp(pnm_last_unixname, nm->unixname) == 0) {
+ (void) fprintf(f, " %s", winname);
+ } else {
+ if (pnm_last_unixname != NULL) {
+ (void) fprintf(f, "\n");
+ free(pnm_last_unixname);
+ }
+ pnm_last_unixname = strdup(nm->unixname);
+ (void) fprintf(f, "%s = %s", nm->unixname, winname);
+ }
+
+ free(winname);
+
+ break;
+ case USERMAP_CFG:
+ if (!nm->is_user) {
+ (void) fprintf(stderr,
+ gettext("Group rule: "));
+ f = stderr;
+ }
+
+ dirstring = direction2string(nm->direction);
+
+ winname_qm = needs_protection(nm->winname) ? "\"" : "";
+ windomain_qm = nm->windomain &&
+ needs_protection(nm->windomain) ? "\"" : "";
+ unixname_qm = needs_protection(nm->unixname) ? "\"" : "";
+
+ if (nm->windomain == NULL)
+ (void) fprintf(f, "%s%s%s\t%s\t%s%s%s\n",
+ winname_qm,
+ nm->winname, winname_qm, dirstring,
+ unixname_qm, nm->unixname, unixname_qm);
+ else
+ (void) fprintf(f, nm->is_nt4 ?
+ "%s%s%1$s\\%3$s%4$s%3$s\t%5$s\t%6$s%7$s%6$s\n" :
+ "%3$s%4$s%3$s@%1$s%2$s%1$s\t%5$s\t%6$s%7$s%6$s\n",
+ windomain_qm, nm->windomain,
+ winname_qm, nm->winname,
+ dirstring,
+ unixname_qm, nm->unixname);
+ break;
+
+ case DEFAULT_FORMAT:
+ /* 'u', 'g' refer to -u, -g switch of idmap add */
+ type = nm->is_user ? 'u' : 'g';
+ if (nm2winqn(nm, &winname1) < 0)
+ return (-1);
+
+ if (shell_app(&winname, winname1)) {
+ free(winname1);
+ return (-1);
+ }
+
+ free(winname1);
+
+ if (nm2unixname(nm, &unixname)) {
+ free(winname);
+ return (-1);
+ }
+
+ if (nm->direction == DIR_U2W) {
+ (void) fprintf(f,
+ "add -%c -d\t%s\t%s\n",
+ type, unixname, winname);
+ } else {
+ (void) fprintf(f,
+ "add -%c %s\t%s\t%s\n",
+ type, nm->direction == DIR_BI ? "" : "-d",
+ winname, unixname);
+ }
+ free(winname);
+ free(unixname);
+ break;
+ default:
+ (void) fprintf(stderr, gettext("Internal error.\n"));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Allocate a new name_mapping_t and initialize the values. */
+static name_mapping_t *
+name_mapping_init() {
+ name_mapping_t *nm = (name_mapping_t *)malloc(sizeof (name_mapping_t));
+ if (nm == NULL) {
+ (void) fprintf(stderr, gettext("Not enough memory.\n"));
+ return (NULL);
+ }
+ nm->winname = nm->windomain = nm->unixname = nm->sidprefix = NULL;
+ nm->rid = UNDEFINED_RID;
+ nm->is_nt4 = B_FALSE;
+ nm->is_user = I_UNKNOWN;
+ nm->direction = DIR_UNKNOWN;
+ nm->pid = UNDEFINED_UID;
+ return (nm);
+}
+
+/* Free name_mapping_t */
+static void
+name_mapping_fini(name_mapping_t *nm) {
+
+ free(nm->winname);
+ free(nm->windomain);
+ free(nm->unixname);
+ free(nm->sidprefix);
+
+ free(nm);
+}
+
+/* Is there exactly one of -g, -u flags? */
+static int
+is_type_determined(flag_t *f)
+{
+ if (f[u_FLAG] == NULL && f[g_FLAG] == NULL || /* none */
+ f[u_FLAG] != NULL && f[g_FLAG] != NULL) /* both */ {
+ (void) fprintf(stderr,
+ gettext("Type (-u|-g) not determined.\n"));
+ return (0);
+ }
+ return (1);
+}
+
+/* Does user request a user-related operation? */
+static int
+is_user_wanted(flag_t *f) {
+ if (f[u_FLAG] != NULL || f[g_FLAG] == NULL)
+ return (1);
+ return (0);
+}
+
+/* Does user request a group-related operation? */
+static int
+is_group_wanted(flag_t *f) {
+ if (f[g_FLAG] != NULL || f[u_FLAG] == NULL)
+ return (1);
+ return (0);
+}
+
+
+/* dump command handler */
+static int
+/* LINTED E_FUNC_ARG_UNUSED */
+do_dump(flag_t *f, int argc, char **argv)
+{
+ idmap_stat stat;
+ idmap_iter_t *ihandle;
+ int is_user;
+ int rc = 0;
+
+ if (init_command())
+ return (-1);
+
+ (void) print_mapping_init(f[n_FLAG] != NULL ? MAPPING_NAME : MAPPING_ID,
+ stdout);
+
+ for (is_user = I_YES; is_user >= I_NO; is_user--) {
+ /*
+ * If there is exactly one of -u, -g flags, we print
+ * only that type. Otherwise both of them:
+ */
+ if (!is_user_wanted(f) && is_user ||
+ !is_group_wanted(f) && !is_user)
+ continue;
+
+ stat = idmap_iter_mappings(handle, is_user, &ihandle);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Iteration handle not obtained (%s)\n"),
+ idmap_stat2string(handle, stat));
+ rc = -1;
+ goto cleanup;
+ }
+
+ do {
+ name_mapping_t *nm = name_mapping_init();
+ if (nm == NULL) {
+ rc = -1;
+ goto cleanup;
+ }
+ nm->is_user = is_user;
+
+
+ stat = idmap_iter_next_mapping(ihandle,
+ &nm->sidprefix, &nm->rid, &nm->pid,
+ &nm->winname, &nm->windomain,
+ &nm->unixname, &nm->direction);
+
+ if (stat >= 0)
+ (void) print_mapping(nm);
+
+ name_mapping_fini(nm);
+
+ } while (stat > 0);
+
+ /* IDMAP_ERR_NOTFOUND indicates end of the list */
+ if (stat < 0 && stat != IDMAP_ERR_NOTFOUND) {
+ (void) fprintf(stderr,
+ gettext("Error during iteration (%s)\n"),
+ idmap_stat2string(handle, stat));
+ rc = -1;
+ goto cleanup;
+ }
+
+ idmap_iter_destroy(ihandle);
+ }
+cleanup:
+ (void) print_mapping_fini();
+ fini_command();
+ return (rc);
+}
+
+/*
+ * The same as strdup, but length chars is duplicated, no matter on
+ * '\0'. The caller must guarantee "length" chars in "from".
+ */
+static char *
+strndup(char *from, size_t length) {
+ char *out = (char *)malloc((length + 1) * sizeof (char));
+ if (out == NULL) {
+ (void) fprintf(stderr, gettext("Not enough memory\n"));
+ return (NULL);
+ }
+ (void) strncpy(out, from, length);
+ out[length] = '\0';
+ return (out);
+}
+
+/* Does line start with USERMAP_CFG IP qualifier? */
+static int
+ucp_is_IP_qualifier(char *line) {
+ char *it;
+ it = line + strcspn(line, " \t\n#:");
+ return (*(it + 1) == ':' ? 1 : 0);
+}
+
+
+/*
+ * returns interior of quotation marks in USERMAP_CFG. In this format,
+ * there cannot be a protected quotation mark inside.
+ */
+static char *
+ucp_qm_interior(char **line, int line_num) {
+ char *out;
+ char *qm = strchr(*line + 1, '"');
+ if (qm == NULL) {
+ (void) fprintf(stderr,
+ gettext("Line %d: Unclosed quotations\n"),
+ line_num);
+ return (NULL);
+ }
+
+ out = strndup(*line + 1, qm - *line - 1);
+ *line = qm + 1;
+ return (out);
+}
+
+/*
+ * Grab next token from the line in USERMAP_CFG format. terminators,
+ * the 3rd parameter, contains all the characters which can terminate
+ * the token. line_num is the line number of input used for error
+ * reporting.
+ */
+static char *
+ucp_grab_token(char **line, int line_num, const char *terminators) {
+ char *token;
+ if (**line == '"')
+ token = ucp_qm_interior(line, line_num);
+ else {
+ int length = strcspn(*line, terminators);
+ token = strndup(*line, length);
+ *line += length;
+ }
+
+ return (token);
+}
+
+
+/*
+ * Convert a line in usermap.cfg format to name_mapping. line_num is
+ * the line number of input used for error reporting.
+ *
+ * Return values: -1 for error, 0 for empty line, 1 for a mapping
+ * found.
+ */
+static int
+ucp_line2nm(char *line, int line_num, name_mapping_t *nm) {
+ char *it;
+ char *token;
+ char *token2;
+ char separator;
+ int is_direction = 0;
+
+ it = line + strspn(line, " \t\n");
+
+ /* empty or comment lines are OK: */
+ if (*it == '\0' || *it == '#')
+ return (0);
+
+ /* We do not support network qualifiers */
+ if (ucp_is_IP_qualifier(it)) {
+ (void) fprintf(stderr,
+ gettext("Line %d: unable to handle network qualifier.\n"),
+ line_num);
+ return (-1);
+ }
+
+ /* The windows name: */
+ token = ucp_grab_token(&it, line_num, " \t#\\\n@=<");
+ if (token == NULL)
+ return (-1);
+
+ separator = *it;
+
+ /* Didn't we bump to the end of line? */
+ if (separator == '\0' || separator == '#') {
+ free(token);
+ (void) fprintf(stderr,
+ gettext("Line %d: UNIX_name not found.\n"),
+ line_num);
+ return (-1);
+ }
+
+ /* Do we have a domainname? */
+ if (separator == '\\' || separator == '@') {
+ it ++;
+ token2 = ucp_grab_token(&it, line_num, " \t\n#");
+ if (token2 == NULL) {
+ free(token);
+ return (-1);
+ } else if (*it == '\0' || *it == '#') {
+ free(token);
+ free(token2);
+ (void) fprintf(stderr,
+ gettext("Line %d: UNIX_name not found.\n"),
+ line_num);
+ }
+
+ if (separator == '\\') {
+ nm->windomain = token;
+ nm->winname = token2;
+ nm->is_nt4 = 1;
+ } else {
+ nm->windomain = token2;
+ nm->winname = token;
+ nm->is_nt4 = 0;
+
+ }
+ } else {
+ nm->windomain = NULL;
+ nm->winname = token;
+ nm->is_nt4 = 0;
+ }
+
+
+ it = it + strspn(it, " \t\n");
+
+ /* Direction string is optional: */
+ if (strncmp(it, "==", 2) == 0) {
+ nm->direction = DIR_BI;
+ is_direction = 1;
+ } else if (strncmp(it, "<=", 2) == 0) {
+ nm->direction = DIR_U2W;
+ is_direction = 1;
+ } else if (strncmp(it, "=>", 2) == 0) {
+ nm->direction = DIR_W2U;
+ is_direction = 1;
+ } else {
+ nm->direction = DIR_BI;
+ is_direction = 0;
+ }
+
+ if (is_direction) {
+ it += 2;
+ it += strspn(it, " \t\n");
+
+ if (*it == '\0' || *it == '#') {
+ (void) fprintf(stderr,
+ gettext("Line %d: UNIX_name not found.\n"),
+ line_num);
+ return (-1);
+ }
+ }
+
+ /* Now unixname: */
+ it += strspn(it, " \t\n");
+ token = ucp_grab_token(&it, line_num, " \t\n#");
+
+ if (token == NULL)
+ /* nm->winname to be freed by name_mapping_fini */
+ return (-1);
+
+ /* Neither here we support IP qualifiers */
+ if (ucp_is_IP_qualifier(token)) {
+ (void) fprintf(stderr,
+ gettext("Line %d: unable to handle network qualifier.\n"),
+ line_num);
+ free(token);
+ return (-1);
+ }
+
+ nm->unixname = token;
+
+ it += strspn(it, " \t\n");
+
+ /* Does something remain on the line */
+ if (*it != '\0' && *it != '#') {
+ (void) fprintf(stderr,
+ gettext("Line %d: unrecognized parameters \"%s\".\n"),
+ line_num, it);
+ return (-1);
+ }
+
+ return (1);
+}
+
+/*
+ * Parse SMBUSERS line to name_mapping_t. if line is NULL, then
+ * pasrsing of the previous line is continued. line_num is input line
+ * number used for error reporting.
+ * Return values:
+ * rc -1: error
+ * rc = 0: mapping found and the line is finished,
+ * rc = 1: mapping found and there remains other on the line
+ */
+static int
+sup_line2nm(char *line, int line_num, name_mapping_t *nm) {
+ static char *ll = NULL;
+ static char *unixname = NULL;
+ static size_t unixname_l = 0;
+ char *token;
+
+ if (line != NULL) {
+ ll = line;
+
+ unixname = ll += strspn(ll, " \t");
+ if (*ll == '\0' || *ll == '#')
+ return (0);
+
+ unixname_l = strcspn(ll, " \t:=#\n");
+ ll += unixname_l;
+
+ if (*ll == '\0'|| *ll == '#')
+ return (0);
+
+ ll += strspn(ll, " \t:=#\n");
+
+ }
+
+ if (*ll == '\0'|| *ll == '#')
+ return (0);
+
+ token = ucp_grab_token(&ll, line_num, " \t\n");
+ if (token == NULL)
+ return (-1);
+
+ nm->is_nt4 = 0;
+ nm->direction = DIR_W2U;
+
+ nm->windomain = NULL;
+ nm->winname = token;
+ nm->unixname = strndup(unixname, unixname_l);
+ if (nm->unixname == NULL)
+ return (-1);
+
+ ll += strspn(ll, " \t\n");
+ return (1);
+}
+
+/* Parse line to name_mapping_t. Basicaly just a format switch. */
+static int
+line2nm(char *line, int line_num, name_mapping_t *nm, format_t f) {
+ switch (f) {
+ case USERMAP_CFG:
+ if (line == NULL)
+ return (0);
+ else
+ return (ucp_line2nm(line, line_num, nm));
+ case SMBUSERS:
+ return (sup_line2nm(line, line_num, nm));
+ default:
+ (void) fprintf(stderr, gettext("Internal error.\n"));
+ }
+
+ return (-1);
+}
+
+
+/* Examine -f flag and return the appropriate format_t */
+static format_t
+ff2format(char *ff, int is_mandatory) {
+
+ if (ff == NULL && is_mandatory) {
+ (void) fprintf(stderr, gettext("Format not given.\n"));
+ return (UNDEFINED_FORMAT);
+ }
+
+ if (ff == NULL)
+ return (DEFAULT_FORMAT);
+
+ if (strcasecmp(ff, "usermap.cfg") == 0)
+ return (USERMAP_CFG);
+
+ if (strcasecmp(ff, "smbusers") == 0)
+ return (SMBUSERS);
+
+ (void) fprintf(stderr,
+ gettext("The only known formats are: \"usermap.cfg\" and "
+ "\"smbusers\".\n"));
+ return (UNDEFINED_FORMAT);
+}
+
+/* Delete all namerules of the given type */
+static int
+flush_nm(boolean_t is_user)
+{
+ idmap_stat stat;
+
+ stat = idmap_udt_flush_namerules(udt, is_user);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ is_user ? gettext("Unable to flush users (%s).\n")
+ : gettext("Unable to flush groups (%s).\n"),
+ idmap_stat2string(handle, stat));
+ return (-1);
+ }
+ return (0);
+}
+
+/* import command handler */
+static int
+/* LINTED E_FUNC_ARG_UNUSED */
+do_import(flag_t *f, int argc, char **argv)
+{
+ name_mapping_t *nm;
+ char line[MAX_INPUT_LINE_SZ];
+ format_t format;
+ int rc = 0;
+ idmap_stat stat;
+ int line_num;
+ FILE *file = NULL;
+
+ if (batch_mode) {
+ (void) fprintf(stderr,
+ gettext("Import is not allowed in the batch mode.\n"));
+ return (-1);
+ }
+
+ format = ff2format(argv[0], 1);
+ if (format == UNDEFINED_FORMAT)
+ return (-1);
+
+ if (init_udt_command())
+ return (-1);
+
+ /* We don't flush groups in the usermap.cfg nor smbusers format */
+ if (f[F_FLAG] != NULL &&
+ flush_nm(B_TRUE) < 0 &&
+ (format == USERMAP_CFG || format == SMBUSERS ||
+ flush_nm(B_FALSE) < 0)) {
+ rc = -1;
+ goto cleanup;
+ }
+
+ line_num = 0;
+
+ /* Where we import from? */
+ if (f[f_FLAG] == NULL)
+ file = stdin;
+ else {
+ file = fopen(f[f_FLAG], "r");
+ if (file == NULL) {
+ perror(f[f_FLAG]);
+ goto cleanup;
+ }
+ }
+
+
+ while (fgets(line, MAX_INPUT_LINE_SZ, file)) {
+ char *line2 = line;
+ line_num++;
+
+ /*
+ * In SMBUSERS format there can be more mappings on
+ * each line. So we need the internal cycle for each line.
+ */
+ do {
+ nm = name_mapping_init();
+ if (nm == NULL) {
+ rc = -1;
+ goto cleanup;
+ }
+
+ rc = line2nm(line2, line_num, nm, format);
+ line2 = NULL;
+
+ if (rc < 1) {
+ name_mapping_fini(nm);
+ break;
+ }
+
+ stat = idmap_udt_add_namerule(udt, nm->windomain,
+ nm->is_user ? B_TRUE : B_FALSE, nm->winname,
+ nm->unixname, nm->is_nt4, nm->direction);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Transaction error (%s)\n"),
+ idmap_stat2string(handle, stat));
+ rc = -1;
+ }
+
+ name_mapping_fini(nm);
+
+ } while (rc >= 0);
+
+ if (rc < 0) {
+ (void) fprintf(stderr,
+ gettext("Import canceled.\n"));
+ break;
+ }
+ }
+
+cleanup:
+ fini_udt_command(rc < 0 ? 0 : 1);
+ if (file != NULL && file != stdin)
+ (void) fclose(file);
+ return (rc);
+}
+
+
+/*
+ * List name mappings in the format specified. list_users /
+ * list_groups determine which type to list. The output goes to the
+ * file fi.
+ */
+static int
+list_name_mappings(int list_users, int list_groups, format_t format, FILE *fi)
+{
+ idmap_stat stat;
+ idmap_iter_t *ihandle;
+ name_mapping_t *nm;
+ int is_user;
+
+ for (is_user = I_YES; is_user >= I_NO; is_user--) {
+ if (is_user && !list_users)
+ continue;
+ if (!is_user && !list_groups)
+ continue;
+ /* Only users can be in USERMAP_CFG format, not a group */
+ if (!is_user && format == USERMAP_CFG)
+ continue;
+
+ stat = idmap_iter_namerules(handle, NULL, is_user, NULL,
+ NULL, &ihandle);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Iteration handle not obtained (%s)\n"),
+ idmap_stat2string(handle, stat));
+ idmap_iter_destroy(ihandle);
+ return (-1);
+ }
+
+ (void) print_mapping_init(format, fi);
+
+ do {
+ nm = name_mapping_init();
+ if (nm == NULL) {
+ idmap_iter_destroy(ihandle);
+ return (-1);
+ }
+
+ stat = idmap_iter_next_namerule(ihandle, &nm->windomain,
+ &nm->winname, &nm->unixname, &nm->is_nt4,
+ &nm->direction);
+ if (stat >= 0) {
+ nm->is_user = is_user;
+ (void) print_mapping(nm);
+ }
+
+ name_mapping_fini(nm);
+
+ } while (stat > 0);
+
+ (void) print_mapping_fini();
+
+ if (stat < 0 && stat != IDMAP_ERR_NOTFOUND) {
+ (void) fprintf(stderr,
+ gettext("Error during iteration (%s)\n"),
+ idmap_stat2string(handle, stat));
+ idmap_iter_destroy(ihandle);
+ return (-1);
+ }
+
+ idmap_iter_destroy(ihandle);
+ }
+ return (0);
+}
+
+/* Export command handler */
+static int
+/* LINTED E_FUNC_ARG_UNUSED */
+do_export(flag_t *f, int argc, char **argv) {
+ int rc;
+ format_t format;
+ FILE *fi;
+
+ format = ff2format(argv[0], 1);
+ if (format == UNDEFINED_FORMAT)
+ return (-1);
+
+ /* Where do we output to? */
+ if (f[f_FLAG] == NULL)
+ fi = stdout;
+ else {
+ fi = fopen(f[f_FLAG], "w");
+ if (fi == NULL) {
+ perror(f[f_FLAG]);
+ return (-1);
+ }
+ }
+
+ if (init_command() < 0) {
+ rc = -1;
+ goto cleanup;
+ }
+
+ /* List the requested types: */
+ rc = list_name_mappings(is_user_wanted(f),
+ is_group_wanted(f),
+ format,
+ fi);
+
+ fini_command();
+
+cleanup:
+ if (fi != NULL && fi != stdout)
+ (void) fclose(fi);
+ return (rc);
+}
+
+/* List command handler */
+static int
+/* LINTED E_FUNC_ARG_UNUSED */
+do_list_name_mappings(flag_t *f, int argc, char **argv)
+{
+ int rc;
+
+ if (init_command()) {
+ return (-1);
+ }
+
+ /* List the requested types: */
+ rc = list_name_mappings(is_user_wanted(f),
+ is_group_wanted(f),
+ DEFAULT_FORMAT,
+ stdout);
+
+ fini_command();
+ return (rc);
+}
+
+/* This is just a debug function for dumping flags */
+static void
+print_flags(flag_t *f)
+{
+ int c;
+ for (c = 0; c < FLAG_ALPHABET_SIZE; c++) {
+ if (f[c] == FLAG_SET)
+ (void) printf("FLAG: -%c, VALUE: %p\n", c,
+ (void *) f[c]);
+ else if (f[c])
+ (void) printf("FLAG: -%c, VALUE: %s\n", c, f[c]);
+ }
+}
+
+/*
+ * Compare two strings just like strcmp, but stop before the end of
+ * the s2
+ */
+static int
+strcmp_no0(const char *s1, const char *s2) {
+ return (strncmp(s1, s2, strlen(s2)));
+}
+
+/* The same as strcmp_no0, but case insensitive. */
+static int
+strcasecmp_no0(const char *s1, const char *s2) {
+ return (strncasecmp(s1, s2, strlen(s2)));
+}
+
+/*
+ * This function splits name to the relevant pieces: is_user, winname,
+ * windomain unixname. Sometimes it is not possible to determine OS
+ * side, because it could be determined by the opposite name in idmap
+ * show. So this function must be called several times.
+ *
+ * Return values: -1 ... clear syntax error
+ * 0 ... it wasnt possible to determine
+ * 1 ... determined
+ */
+static int
+name2parts(char *name, name_mapping_t *nm) {
+ char *it;
+ int is_win = I_NO;
+ int is_unix = I_NO;
+
+ if (nm->winname != NULL && nm->unixname != NULL)
+ return (0);
+
+ /* If it starts with type string, that is easy: */
+ if (it = strchr(name, ':')) {
+ if (strcmp_no0(name, ID_UNIXNAME ":") == 0) {
+ if (nm->unixname != NULL)
+ return (0);
+ is_unix = I_YES;
+ } else if (strcmp_no0(name, ID_WINNAME ":") == 0) {
+ if (nm->winname != NULL)
+ return (0);
+ is_win = I_YES;
+ } else {
+ (void) fprintf(stderr,
+ gettext("Error: invalid identity type\n"));
+ return (-1);
+ }
+ name = it + 1;
+ }
+
+ /* If it contains '@' or '\\', then it is a winname with domain */
+ if (!is_unix && nm->winname == NULL) {
+ if ((it = strchr(name, '@')) != NULL) {
+ int length = it-name+1;
+ nm->winname = (char *)malloc(length * sizeof (char));
+ (void) strncpy(nm->winname, name, length - 1);
+ nm->winname[length - 1] = '\0';
+ nm->windomain = strdup(it + 1);
+ return (1);
+ } else if ((it = strrchr(name, '\\')) != NULL) {
+ int length = it-name+1;
+ nm->windomain = (char *)malloc(length * sizeof (char));
+ (void) strncpy(nm->windomain, name, length - 1);
+ nm->windomain[length - 1] = '\0';
+ nm->winname = strdup(it + 1);
+ nm->is_nt4 = B_TRUE;
+ return (1);
+ }
+ }
+
+ /*
+ * if is_unix/is_win is not yet determined, then the last
+ * hope is that the opposite side is known already. In that
+ * case, it is the only remaining side.
+ */
+ if (is_unix || nm->unixname == NULL && nm->winname != NULL) {
+ if (strlen(name) == 0)
+ nm->unixname = strdup("\"\"");
+ else
+ nm->unixname = strdup(name);
+ return (1);
+ } else if (is_win || nm->unixname != NULL && nm->winname == NULL) {
+ if (strlen(name) == 0)
+ nm->winname = strdup("\"\"");
+ else
+ nm->winname = strdup(name);
+ nm->windomain = NULL;
+ return (1);
+ }
+
+ return (0);
+}
+
+/* add command handler. */
+static int
+do_add_name_mapping(flag_t *f, int argc, char **argv)
+{
+ name_mapping_t *nm;
+ int rc = 0;
+ int i;
+ int is_argv0_unix = -1;
+ idmap_stat stat;
+
+
+ /* Two arguments and exactly one of -u, -g must be specified */
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("Not enough arguments.\n"));
+ return (-1);
+ } else if (argc > 2) {
+ (void) fprintf(stderr, gettext("Too many arguments.\n"));
+ return (-1);
+ } else if (!is_type_determined(f))
+ return (-1);
+
+ /*
+ * Direction can be determined by the opposite name, so we
+ * need to run name2parts twice for the first name, i.e. 3x in
+ * total.
+ */
+ nm = name_mapping_init();
+ if (nm == NULL)
+ return (-1);
+
+ nm->is_user = f[u_FLAG] != NULL ? I_YES : I_NO;
+
+ for (i = 0; i < 3; i++) {
+ switch (name2parts(argv[i % 2], nm)) {
+ case -1:
+ name_mapping_fini(nm);
+ return (-1);
+ case 1:
+ if (is_argv0_unix < 0)
+ is_argv0_unix =
+ i % 2 ^ (nm->unixname != NULL ? 1 : 0);
+ break;
+ }
+ }
+
+ if (nm->winname == NULL || nm->unixname == NULL) {
+ (void) fprintf(stderr, gettext("Name types not determined.\n"));
+ name_mapping_fini(nm);
+ return (-1);
+ }
+
+ if (f[d_FLAG] != NULL)
+ nm->direction = is_argv0_unix ? DIR_U2W : DIR_W2U;
+ else
+ nm->direction = DIR_BI;
+
+ /* Now let us write it: */
+
+ if (init_udt_command()) {
+ name_mapping_fini(nm);
+ return (-1);
+ }
+
+ stat = idmap_udt_add_namerule(udt, nm->windomain,
+ nm->is_user ? B_TRUE : B_FALSE, nm->winname, nm->unixname,
+ nm->is_nt4, nm->direction);
+
+ /* We echo the mapping */
+ (void) print_mapping_init(DEFAULT_FORMAT, stdout);
+ (void) print_mapping(nm);
+ (void) print_mapping_fini();
+
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Mapping not created (%s)\n"),
+ idmap_stat2string(handle, stat));
+ rc = -1;
+ }
+
+cleanup:
+ name_mapping_fini(nm);
+ fini_udt_command(1);
+ return (rc);
+}
+
+/* remove command handler */
+static int
+do_remove_name_mapping(flag_t *f, int argc, char **argv)
+{
+ name_mapping_t *nm;
+ int rc = 0;
+ int i;
+ int is_argv0_unix = -1;
+ idmap_stat stat;
+
+ /* "-a" means we flush all of them */
+ if (f[a_FLAG] != NULL) {
+ if (argc) {
+ (void) fprintf(stderr,
+ gettext("Too many arguments.\n"));
+ return (-1);
+ }
+
+ if (!is_type_determined(f))
+ return (-1);
+
+ if (init_udt_command())
+ return (-1);
+ rc = flush_nm(f[u_FLAG] != NULL ? B_TRUE : B_FALSE);
+
+ fini_udt_command(rc ? 0 : 1);
+ return (rc);
+ }
+
+ /* Contrary to add_name_mapping, we can have only one argument */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("Not enough arguments.\n"));
+ return (-1);
+ } else if (argc > 2) {
+ (void) fprintf(stderr, gettext("Too many arguments.\n"));
+ return (-1);
+ } else if (!is_type_determined(f)) {
+ return (-1);
+ } else if (
+ /* both -f and -t: */
+ f[f_FLAG] != NULL && f[t_FLAG] != NULL ||
+ /* -d with a single argument: */
+ argc == 1 && f[d_FLAG] != NULL ||
+ /* -f or -t with two arguments: */
+ argc == 2 && (f[f_FLAG] != NULL || f[t_FLAG] != NULL)) {
+ (void) fprintf(stderr,
+ gettext("Direction ambiguous.\n"));
+ return (-1);
+ }
+
+
+ /*
+ * Similar to do_add_name_mapping - see the comments
+ * there. Except we may have only one argument here.
+ */
+ nm = name_mapping_init();
+ if (nm == NULL)
+ return (-1);
+
+ nm->is_user = f[u_FLAG] != NULL ? I_YES : I_NO;
+
+ for (i = 0; i < 2 * argc - 1; i++) {
+ switch (name2parts(argv[i % 2], nm)) {
+ case -1:
+ name_mapping_fini(nm);
+ return (-1);
+ case 1:
+ if (is_argv0_unix < 0)
+ is_argv0_unix = i % 2 ^ (nm->unixname ? 1 : 0);
+ break;
+ }
+ }
+
+
+ if (nm->winname == NULL && nm->unixname == NULL) {
+ (void) fprintf(stderr, gettext("Name types not determined.\n"));
+ name_mapping_fini(nm);
+ return (-1);
+ }
+
+ /*
+ * If the direction is not specified by a -d/-f/-t flag, then it
+ * is DIR_UNKNOWN, because in that case we want to remove any
+ * mapping. If it was DIR_BI, idmap_api would delete a
+ * bidirectional one only.
+ */
+ if (f[d_FLAG] != NULL || f[f_FLAG] != NULL)
+ nm->direction = is_argv0_unix ? DIR_U2W : DIR_W2U;
+ else if (f[t_FLAG] != NULL)
+ nm->direction = is_argv0_unix ? DIR_W2U : DIR_U2W;
+ else
+ nm->direction = DIR_UNKNOWN;
+
+ if (init_udt_command()) {
+ name_mapping_fini(nm);
+ return (-1);
+ }
+
+ stat = idmap_udt_rm_namerule(udt, nm->is_user ? B_TRUE : B_FALSE,
+ nm->windomain, nm->winname, nm->unixname, nm->direction);
+
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Mapping not deleted (%s)\n"),
+ idmap_stat2string(handle, stat));
+ rc = -1;
+ }
+
+cleanup:
+ name_mapping_fini(nm);
+ fini_udt_command(1);
+ return (rc);
+}
+
+
+/* exit command handler */
+static int
+/* LINTED E_FUNC_ARG_UNUSED */
+do_exit(flag_t *f, int argc, char **argv) {
+ return (0);
+}
+
+
+/* debug command handler: just print the parameters */
+static int
+/* LINTED E_STATIC_UNUSED */
+debug_print_params(flag_t *f, int argc, char **argv)
+{
+ int i;
+#if 0
+ char *leaktest = (char *)malloc(100);
+#endif
+
+ print_flags(f);
+
+ for (i = 0; i < argc; i++) {
+ (void) printf("Argument %d: %s\n", i, argv[i]);
+ }
+
+ (void) fflush(stdout);
+ return (0);
+}
+
+/*
+ * Return a pointer after a given prefix. If there is no such prefix,
+ * return NULL
+ */
+static char *
+get_root(char *string, char *typestring) {
+ if (strcasecmp_no0(string, typestring) != 0)
+ return (NULL);
+ return (string + strlen(typestring));
+}
+
+/*
+ * From name_mapping_t, asseble a string containing identity of the
+ * given type.
+ */
+static int
+nm2type(name_mapping_t *nm, int type, char **to) {
+ switch (type) {
+ case TYPE_SID:
+ if (nm->sidprefix == NULL)
+ return (-1);
+ *to = sid_format(nm->sidprefix, nm->rid);
+ return (0);
+ case TYPE_WN:
+ return (nm2winqn(nm, to));
+ case TYPE_UID:
+ case TYPE_GID:
+ case TYPE_PID:
+ *to = pid_format(nm->pid, nm->is_user);
+ if (*to == NULL)
+ return (-1);
+ else
+ return (0);
+ case TYPE_UN:
+ return (nm2unixname(nm, to));
+ default:
+ (void) fprintf(stderr, gettext("Internal error.\n"));
+ return (-1);
+ }
+ /* never reached */
+}
+
+/* show command handler */
+static int
+do_show_mapping(flag_t *f, int argc, char **argv)
+{
+ idmap_stat stat = 0;
+ int flag;
+ idmap_stat map_stat = 0;
+ int type_from;
+ int type_to;
+ char *root;
+ name_mapping_t *nm = NULL;
+ char *fromname;
+ char *toname;
+
+ if (argc == 0) {
+ (void) fprintf(stderr,
+ gettext("No identity given\n"));
+ return (-1);
+ } else if (argc > 2) {
+ (void) fprintf(stderr,
+ gettext("Too many arguments.\n"));
+ return (-1);
+ }
+
+ flag = f[c_FLAG] != NULL ? 0 : IDMAP_REQ_FLG_NO_NEW_ID_ALLOC;
+
+ if (init_command())
+ return (-1);
+
+ nm = name_mapping_init();
+ if (nm == NULL)
+ goto cleanup;
+
+ /* First, determine type_from: */
+ if ((root = get_root(argv[0], ID_UID ":")) != NULL)
+ type_from = TYPE_UID;
+ else if ((root = get_root(argv[0], ID_GID ":")) != NULL)
+ type_from = TYPE_GID;
+ else if ((root = get_root(argv[0], ID_SID ":")) != NULL)
+ type_from = TYPE_SID;
+ else if (name2parts(argv[0], nm) > 0) {
+ if (nm->unixname != NULL)
+ type_from = TYPE_UN;
+ else
+ type_from = TYPE_WN;
+ } else {
+ (void) fprintf(stderr,
+ gettext("Invalid type.\n"));
+ stat = IDMAP_ERR_ARG;
+ goto cleanup;
+ }
+
+ /* Second, determine type_to: */
+ if (argc < 2) {
+ type_to = type_from & IS_WIN ? TYPE_PID : TYPE_SID;
+ if (type_from & IS_NAME)
+ type_to |= IS_NAME;
+ } else if (strcasecmp(argv[1], ID_UID) == 0)
+ type_to = TYPE_UID;
+ else if (strcasecmp(argv[1], ID_GID) == 0)
+ type_to = TYPE_GID;
+ else if (strcasecmp(argv[1], ID_SID) == 0)
+ type_to = TYPE_SID;
+ else if (strcmp(argv[1], ID_UNIXNAME) == 0)
+ type_to = TYPE_UN;
+ else if (strcmp(argv[1], ID_WINNAME) == 0)
+ type_to = TYPE_WN;
+ else {
+ (void) fprintf(stderr,
+ gettext("Ivnalid target type.\n"));
+ stat = IDMAP_ERR_ARG;
+ goto cleanup;
+ }
+
+ /* Are both arguments the same OS side? */
+ if (!(type_from & IS_WIN ^ type_to & IS_WIN)) {
+ (void) fprintf(stderr,
+ gettext("Direction ambiguous.\n"));
+ stat = IDMAP_ERR_ARG;
+ goto cleanup;
+ }
+
+ if (type_from == TYPE_SID) {
+ char *p, *end, *sid;
+ sid = argv[0] + 4;
+ if ((p = strrchr(sid, '-')) == NULL) {
+ (void) fprintf(stderr,
+ gettext("Invalid SID %s\n"), sid);
+ goto cleanup;
+ }
+ /* Replace '-' by string terminator so that sid = sidprefix */
+ *p = 0;
+ nm->sidprefix = strdup(sid);
+ nm->rid = strtoll(p + 1, &end, 10);
+ /* Restore '-' */
+ *p = '-';
+
+ } else if (type_from == TYPE_UID || type_from == TYPE_GID) {
+ nm->pid = (uid_t)atol(root);
+ }
+
+/*
+ * We have two interfaces for retrieving the mappings:
+ * idmap_get_sidbyuid & comp (the batch interface) and
+ * idmap_get_w2u_mapping & comp. We want to use both of them, because
+ * the former mimicks kernel interface better and the later offers the
+ * string names. In the batch case, our batch has always size 1.
+ */
+ if (type_from & IS_NAME || type_to & IS_NAME) {
+ if (type_from & IS_WIN) {
+ if (type_to == TYPE_UID)
+ nm->is_user = I_YES;
+ else if (type_to == TYPE_GID)
+ nm->is_user = I_NO;
+
+ map_stat = idmap_get_w2u_mapping(handle,
+ nm->sidprefix,
+ &nm->rid,
+ nm->winname,
+ nm->windomain,
+ flag,
+ &nm->is_user,
+ &nm->pid,
+ &nm->unixname,
+ &nm->direction);
+ } else {
+ if (type_from == TYPE_UID)
+ nm->is_user = I_YES;
+ else if (type_from == TYPE_GID)
+ nm->is_user = I_NO;
+
+ map_stat = idmap_get_u2w_mapping(handle,
+ &nm->pid,
+ nm->unixname,
+ flag,
+ nm->is_user,
+ &nm->sidprefix,
+ &nm->rid,
+ &nm->winname,
+ &nm->windomain,
+ &nm->direction);
+ }
+
+ } else {
+ /* batch handle */
+ idmap_get_handle_t *ghandle = NULL;
+ /* To be passed to idmap_get_uidbysid */
+ gid_t gid = UNDEFINED_GID;
+ /* To be passed to idmap_get_gidbysid */
+ uid_t uid = UNDEFINED_UID;
+
+
+ /* Create an in-memory structure for all the batch: */
+ stat = idmap_get_create(handle, &ghandle);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Unable to create handle for communicating"
+ " with idmapd(1M) (%s)\n"),
+ idmap_stat2string(handle, stat));
+ idmap_get_destroy(ghandle);
+ goto cleanup;
+ }
+
+ /* Schedule the request: */
+ if (type_from == TYPE_SID && type_to == TYPE_UID) {
+ stat = idmap_get_uidbysid(ghandle,
+ nm->sidprefix,
+ nm->rid,
+ flag,
+ &uid,
+ &map_stat);
+ nm->is_user = I_YES;
+ } else if (type_from == TYPE_SID && type_to == TYPE_GID) {
+ stat = idmap_get_gidbysid(ghandle,
+ nm->sidprefix,
+ nm->rid,
+ flag,
+ &gid,
+ &map_stat);
+ nm->is_user = I_NO;
+ } else if (type_from == TYPE_SID && type_to == TYPE_PID)
+ stat = idmap_get_pidbysid(ghandle,
+ nm->sidprefix,
+ nm->rid,
+ flag,
+ &nm->pid,
+ &nm->is_user,
+ &map_stat);
+ else if (type_from == TYPE_UID && type_to == TYPE_SID) {
+ stat = idmap_get_sidbyuid(ghandle,
+ nm->pid,
+ flag,
+ &nm->sidprefix,
+ &nm->rid,
+ &map_stat);
+ nm->is_user = I_YES;
+ } else if (type_from == TYPE_GID && type_to == TYPE_SID) {
+ stat = idmap_get_sidbygid(ghandle,
+ (gid_t)nm->pid,
+ flag,
+ &nm->sidprefix,
+ &nm->rid,
+ &map_stat);
+ nm->is_user = I_NO;
+ } else {
+ (void) fprintf(stderr, gettext("Internal error.\n"));
+ exit(1);
+ }
+
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Request for %.3s not sent (%s)\n"),
+ argv[0], idmap_stat2string(handle, stat));
+ idmap_get_destroy(ghandle);
+ goto cleanup;
+ }
+
+ /* Send the batch to idmapd and obtain results: */
+ stat = idmap_get_mappings(ghandle);
+ if (stat < 0) {
+ (void) fprintf(stderr,
+ gettext("Mappings not obtained because of"
+ " RPC problem (%s)\n"),
+ idmap_stat2string(handle, stat));
+ idmap_get_destroy(ghandle);
+ goto cleanup;
+ }
+
+ /* Destroy the batch handle: */
+ idmap_get_destroy(ghandle);
+
+ if (type_to == TYPE_UID)
+ nm->pid = uid;
+ else if (type_to == TYPE_GID)
+ nm->pid = (uid_t)gid;
+
+ }
+
+ /*
+ * If there was -c flag, we do output whatever we can even in
+ * the case of error:
+ */
+ if (map_stat < 0) {
+ (void) fprintf(stderr,
+ gettext("%s\n"),
+ idmap_stat2string(handle, map_stat));
+ if (flag == IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
+ goto cleanup;
+ }
+
+
+ if (nm2type(nm, type_from, &fromname) < 0)
+ goto cleanup;
+
+ if (nm2type(nm, type_to, &toname) < 0) {
+ if (flag == 0)
+ (void) printf("%s -> %s:%u\n",
+ fromname,
+ (type_from | type_to) & IS_GROUP ? ID_GID : ID_UID,
+ UID_NOBODY);
+ free(fromname);
+ goto cleanup;
+ }
+
+ (void) printf("%s -> %s\n", fromname, toname);
+ free(fromname);
+ free(toname);
+
+cleanup:
+ if (nm != NULL)
+ name_mapping_fini(nm);
+ fini_command();
+ return (stat < 0 || map_stat < 0 ? -1 : 0);
+}
+
+/* main function. Returns 1 for error, 0 otherwise */
+int
+main(int argc, char *argv[]) {
+ int rc;
+
+ /* set locale and domain for internationalization */
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ /* idmap_engine determines the batch_mode: */
+ rc = engine_init(sizeof (commands) / sizeof (cmd_ops_t),
+ commands,
+ argc - 1,
+ argv + 1,
+ &batch_mode);
+
+ if (rc < 0) {
+ (void) engine_fini();
+ if (rc == IDMAP_ENG_ERROR_SILENT)
+ help();
+ return (1);
+ }
+
+ udt_used = 0;
+ if (batch_mode) {
+ if (init_udt_batch() < 0)
+ return (1);
+ }
+
+ idmap_set_verbose(FALSE);
+ rc = run_engine(argc - 1, argv + 1);
+
+ if (batch_mode) {
+ batch_mode = 0;
+ fini_udt_command(rc == 0 ? 1 : 0);
+ }
+
+ (void) engine_fini();
+ return (rc == 0 ? 0 : 1);
+}
diff --git a/usr/src/cmd/idmap/idmap/idmap_engine.c b/usr/src/cmd/idmap/idmap/idmap_engine.c
new file mode 100644
index 0000000000..31385c693c
--- /dev/null
+++ b/usr/src/cmd/idmap/idmap/idmap_engine.c
@@ -0,0 +1,576 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <locale.h>
+#include <ctype.h>
+#ifdef WITH_LIBTECLA
+#include <libtecla.h>
+#endif
+#include "idmap_engine.h"
+
+/* The maximal line length. Longer lines may not be parsed OK. */
+#define MAX_CMD_LINE_SZ 1023
+
+#ifdef WITH_LIBTECLA
+#define MAX_HISTORY_LINES 1023
+static GetLine * gl_h;
+/* LINTED E_STATIC_UNUSED */
+#endif
+
+/* Array for arguments of the actuall command */
+static char ** my_argv;
+/* Allocated size for my_argv */
+static int my_argv_size = 16;
+/* Actuall length of my_argv */
+static int my_argc;
+
+/* Array for subcommands */
+static cmd_ops_t *my_comv;
+/* my_comc length */
+static int my_comc;
+
+/* Input filename specified by the -f flag */
+static char *my_filename;
+
+/*
+ * Batch mode means reading file, stdin or libtecla input. Shell input is
+ * a non-batch mode.
+ */
+static int my_batch_mode;
+
+/* Array of all possible flags */
+static flag_t flags[FLAG_ALPHABET_SIZE];
+
+/* getopt variables */
+extern char *optarg;
+extern int optind, optopt, opterr;
+
+/* Fill the flags array: */
+static int
+options_parse(int argc, char *argv[], const char *options)
+{
+ char c;
+
+ optind = 1;
+
+ while ((c = getopt(argc, argv, options)) != EOF) {
+ switch (c) {
+ case '?':
+ return (-1);
+ case ':':
+ /* This is relevant only if options starts with ':': */
+ (void) fprintf(stderr,
+ gettext("Option %s: missing parameter\n"),
+ argv[optind - 1]);
+ return (-1);
+ default:
+ if (optarg == NULL)
+ flags[c] = FLAG_SET;
+ else
+ flags[c] = optarg;
+
+ }
+ }
+ return (optind);
+}
+
+/* Unset all flags */
+static void
+options_clean()
+{
+ (void) memset(flags, 0, FLAG_ALPHABET_SIZE * sizeof (flag_t));
+}
+
+/* determine which subcommand is argv[0] and execute its handler */
+static int
+run_command(int argc, char **argv) {
+ int i;
+
+ if (argc == 0) {
+ if (my_batch_mode)
+ return (0);
+ return (-1);
+ }
+ for (i = 0; i < my_comc; i++) {
+ int optind;
+ int rc;
+
+ if (strcmp(my_comv[i].cmd, argv[0]) != 0)
+ continue;
+
+ /* We found it. Now execute the handler. */
+ options_clean();
+ optind = options_parse(argc, argv, my_comv[i].options);
+ if (optind < 0) {
+ return (-1);
+ }
+
+ rc = my_comv[i].p_do_func(flags, argc - optind, argv + optind);
+
+ return (rc);
+ }
+
+ (void) fprintf(stderr, gettext("Unknown command %s\n"),
+ argv[0]);
+
+ return (-1);
+
+}
+
+/*
+ * Read another parameter from "from", up to a space char (unless it
+ * is quoted). Duplicate it to "to". Remove quotation, if any.
+ */
+static int
+get_param(char **to, const char *from) {
+ int to_i, from_i;
+ char c;
+ int last_slash = 0; /* Preceded by a slash? */
+ int in_string = 0; /* Inside quites? */
+ int is_param = 0;
+ size_t buf_size = 20; /* initial length of the buffer. */
+ char *buf = (char *)malloc(buf_size * sizeof (char));
+
+ from_i = 0;
+ while (isspace(from[from_i]))
+ from_i++;
+
+ for (to_i = 0; '\0' != from[from_i]; from_i++) {
+ c = from[from_i];
+
+ if (to_i >= buf_size - 1) {
+ buf_size *= 2;
+ buf = (char *)realloc(buf, buf_size * sizeof (char));
+ }
+
+ if (c == '"' && !last_slash) {
+ in_string = !in_string;
+ is_param = 1;
+ continue;
+
+ } else if (c == '\\' && !last_slash) {
+ last_slash = 1;
+ continue;
+
+ } else if (!last_slash && !in_string && isspace(c)) {
+ break;
+ }
+
+ buf[to_i++] = from[from_i];
+ last_slash = 0;
+
+ }
+
+ if (to_i == 0 && !is_param) {
+ free(buf);
+ *to = NULL;
+ return (0);
+ }
+
+ buf[to_i] = '\0';
+ *to = buf;
+
+ if (in_string)
+ return (-1);
+
+ return (from_i);
+}
+
+/*
+ * Split a string to a parameter array and append it to the specified position
+ * of the array
+ */
+static int
+line2array(const char *line)
+{
+ const char *cur;
+ char *param;
+ int len;
+
+ for (cur = line; len = get_param(&param, cur); cur += len) {
+ if (my_argc > my_argv_size) {
+ my_argv_size *= 2;
+ my_argv = (char **)realloc(my_argv,
+ my_argv_size * sizeof (char *));
+ }
+
+ my_argv[my_argc] = param;
+ ++my_argc;
+
+ /* quotation not closed */
+ if (len < 0)
+ return (-1);
+
+ }
+ return (0);
+
+}
+
+/* Clean all aruments from my_argv. Don't deallocate my_argv itself. */
+static void
+my_argv_clean()
+{
+ int i;
+ for (i = 0; i < my_argc; i++) {
+ free(my_argv[i]);
+ my_argv[i] = NULL;
+ }
+ my_argc = 0;
+}
+
+
+#ifdef WITH_LIBTECLA
+/* This is libtecla tab completion. */
+static
+CPL_MATCH_FN(command_complete)
+{
+ /*
+ * WordCompletion *cpl; const char *line; int word_end are
+ * passed from the CPL_MATCH_FN macro.
+ */
+ int i;
+ char *prefix;
+ int prefix_l;
+
+ /* We go on even if quotation is not closed */
+ (void) line2array(line);
+
+
+ /* Beginning of the line: */
+ if (my_argc == 0) {
+ for (i = 0; i < my_comc; i++)
+ (void) cpl_add_completion(cpl, line, word_end,
+ word_end, my_comv[i].cmd, "", " ");
+ goto cleanup;
+ }
+
+ /* Is there something to complete? */
+ if (isspace(line[word_end - 1]))
+ goto cleanup;
+
+ prefix = my_argv[my_argc - 1];
+ prefix_l = strlen(prefix);
+
+ /* Subcommand name: */
+ if (my_argc == 1) {
+ for (i = 0; i < my_comc; i++)
+ if (strncmp(prefix, my_comv[i].cmd, prefix_l) == 0)
+ (void) cpl_add_completion(cpl, line,
+ word_end - prefix_l,
+ word_end, my_comv[i].cmd + prefix_l,
+ "", " ");
+ goto cleanup;
+ }
+
+ /* Long options: */
+ if (prefix[0] == '-' && prefix [1] == '-') {
+ char *options2 = NULL;
+ char *paren;
+ char *thesis;
+ int i;
+
+ for (i = 0; i < my_comc; i++)
+ if (0 == strcmp(my_comv[i].cmd, my_argv[0])) {
+ options2 = strdup(my_comv[i].options);
+ break;
+ }
+
+ /* No such subcommand, or not enough memory: */
+ if (options2 == NULL)
+ goto cleanup;
+
+ for (paren = strchr(options2, '(');
+ paren && ((thesis = strchr(paren + 1, ')')) != NULL);
+ paren = strchr(thesis + 1, '(')) {
+ /* Short option or thesis must precede, so this is safe: */
+ *(paren - 1) = '-';
+ *paren = '-';
+ *thesis = '\0';
+ if (strncmp(paren - 1, prefix, prefix_l) == 0) {
+ (void) cpl_add_completion(cpl, line,
+ word_end - prefix_l,
+ word_end, paren - 1 + prefix_l, "", " ");
+ }
+ }
+ free(options2);
+
+ /* "--" is a valid completion */
+ if (prefix_l == 2) {
+ (void) cpl_add_completion(cpl, line,
+ word_end - 2,
+ word_end, "", "", " ");
+ }
+
+ }
+
+cleanup:
+ my_argv_clean();
+ return (0);
+}
+
+/* libtecla subshell: */
+static int
+interactive_interp()
+{
+ int rc = 0;
+ char *prompt;
+ const char *line;
+
+ (void) sigset(SIGINT, SIG_IGN);
+
+ gl_h = new_GetLine(MAX_CMD_LINE_SZ, MAX_HISTORY_LINES);
+
+ if (gl_h == NULL) {
+ (void) fprintf(stderr,
+ gettext("Error reading terminal: %s.\n"),
+ gl_error_message(gl_h, NULL, 0));
+ return (-1);
+ }
+
+ (void) gl_customize_completion(gl_h, NULL, command_complete);
+
+ for (;;) {
+new_line:
+ my_argv_clean();
+ prompt = "> ";
+continue_line:
+ line = gl_get_line(gl_h, prompt, NULL, -1);
+
+ if (line == NULL) {
+ switch (gl_return_status(gl_h)) {
+ case GLR_SIGNAL:
+ gl_abandon_line(gl_h);
+ goto new_line;
+
+ case GLR_EOF:
+ (void) line2array("exit");
+ break;
+
+ case GLR_ERROR:
+ (void) fprintf(stderr,
+ gettext("Error reading terminal: %s.\n"),
+ gl_error_message(gl_h, NULL, 0));
+ rc = -1;
+ goto end_of_input;
+ default:
+ (void) fprintf(stderr, "Internal error.\n");
+ exit(1);
+ }
+ } else {
+ if (line2array(line) < 0) {
+ (void) fprintf(stderr,
+ gettext("Quotation not closed\n"));
+ goto new_line;
+ }
+ if (my_argc == 0) {
+ goto new_line;
+ }
+ if (strcmp(my_argv[my_argc-1], "\n") == 0) {
+ my_argc--;
+ free(my_argv[my_argc]);
+ (void) strcpy(prompt, "> ");
+ goto continue_line;
+ }
+ }
+
+ rc = run_command(my_argc, my_argv);
+
+ if (strcmp(my_argv[0], "exit") == 0 && rc == 0) {
+ break;
+ }
+
+ }
+
+end_of_input:
+ gl_h = del_GetLine(gl_h);
+ my_argv_clean();
+ return (rc);
+}
+#endif
+
+/* Interpretation of a source file given by "name" */
+static int
+source_interp(const char *name)
+{
+ FILE *f;
+ int is_stdin;
+ int rc = -1;
+ char line[MAX_CMD_LINE_SZ];
+
+ if (name == NULL || strcmp("-", name) == 0) {
+ f = stdin;
+ is_stdin = 1;
+ } else {
+ is_stdin = 0;
+ f = fopen(name, "r");
+ if (f == NULL) {
+ perror(name);
+ return (-1);
+ }
+ }
+
+ while (fgets(line, MAX_CMD_LINE_SZ, f)) {
+
+ if (line2array(line) < 0) {
+ (void) fprintf(stderr,
+ gettext("Quotation not closed\n"));
+ my_argv_clean();
+ continue;
+ }
+
+ /* We do not wan't "\n" as the last parameter */
+ if (my_argc != 0 && strcmp(my_argv[my_argc-1], "\n") == 0) {
+ my_argc--;
+ free(my_argv[my_argc]);
+ continue;
+ }
+
+ if (my_argc != 0 && strcmp(my_argv[0], "exit") == 0) {
+ rc = 0;
+ my_argv_clean();
+ break;
+ }
+
+ rc = run_command(my_argc, my_argv);
+ my_argv_clean();
+ }
+
+ if (my_argc > 0) {
+ (void) fprintf(stderr, gettext("Line continuation missing\n"));
+ rc = 1;
+ my_argv_clean();
+ }
+
+ if (!is_stdin)
+ (void) fclose(f);
+
+ return (rc);
+}
+
+/*
+ * Initialize the engine.
+ * comc, comv is the array of subcommands and its length,
+ * argc, argv are arguments to main to be scanned for -f filename and
+ * the length og the array,
+ * is_batch_mode passes to the caller the information if the
+ * batch mode is on.
+ *
+ * Return values:
+ * 0: ... OK
+ * IDMAP_ENG_ERROR: error and message printed already
+ * IDMAP_ENG_ERROR_SILENT: error and message needs to be printed
+ *
+ */
+
+int
+engine_init(int comc, cmd_ops_t *comv, int argc, char **argv,
+ int *is_batch_mode) {
+ int c;
+
+ my_comc = comc;
+ my_comv = comv;
+
+ my_argc = 0;
+ my_argv = (char **)calloc(my_argv_size, sizeof (char *));
+
+ if (argc < 1) {
+ my_filename = NULL;
+ if (isatty(fileno(stdin))) {
+#ifdef WITH_LIBTECLA
+ my_batch_mode = 1;
+#else
+ my_batch_mode = 0;
+ return (IDMAP_ENG_ERROR_SILENT);
+#endif
+ } else
+ my_batch_mode = 1;
+
+ goto the_end;
+ }
+
+ my_batch_mode = 0;
+
+ optind = 0;
+ while ((c = getopt(argc, argv,
+ "f:(command-file)")) != EOF) {
+ switch (c) {
+ case '?':
+ return (IDMAP_ENG_ERROR);
+ case 'f':
+ my_batch_mode = 1;
+ my_filename = optarg;
+ break;
+ default:
+ (void) fprintf(stderr, "Internal error.\n");
+ exit(1);
+ }
+ }
+
+the_end:
+
+ if (is_batch_mode != NULL)
+ *is_batch_mode = my_batch_mode;
+ return (0);
+}
+
+/* finitialize the engine */
+int
+engine_fini() {
+ my_argv_clean();
+ free(my_argv);
+ return (0);
+}
+
+/*
+ * Interpret the subcommands defined by the arguments, unless
+ * my_batch_mode was set on in egnine_init.
+ */
+int
+run_engine(int argc, char **argv)
+{
+ int rc = -1;
+
+ if (my_batch_mode) {
+#ifdef WITH_LIBTECLA
+ if (isatty(fileno(stdin)))
+ rc = interactive_interp();
+ else
+#endif
+ rc = source_interp(my_filename);
+ goto cleanup;
+ }
+
+ rc = run_command(argc, argv);
+
+cleanup:
+ return (rc);
+}
diff --git a/usr/src/cmd/idmap/idmap/idmap_engine.h b/usr/src/cmd/idmap/idmap/idmap_engine.h
new file mode 100644
index 0000000000..3731598c8d
--- /dev/null
+++ b/usr/src/cmd/idmap/idmap/idmap_engine.h
@@ -0,0 +1,68 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _IDMAP_ENGINE_H
+#define _IDMAP_ENGINE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Debug macros */
+#define DPTR(a) printf("%s::%d %s = %p\n", __FILE__, __LINE__, #a, a);
+#define DSTRING(a) printf("%s::%d %s = \"%s\"\n", __FILE__, __LINE__, #a, \
+ a ? a : "(null)");
+#define DINT(a) printf("%s::%d %s = %d\n", __FILE__, __LINE__, #a, a);
+#define DHEX(a) printf("%s::%d %s = %X\n", __FILE__, __LINE__, #a, a);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char *flag_t;
+#define FLAG_SET (char *)1
+#define FLAG_ALPHABET_SIZE 255
+
+#define IDMAP_ENG_OK 0
+#define IDMAP_ENG_ERROR -1
+#define IDMAP_ENG_ERROR_SILENT -2
+
+typedef struct cmd_ops {
+ const char *cmd; /* the subcommand */
+ const char *options; /* getopt string for the subcommand params */
+ int (*p_do_func)(flag_t *f, int argc, char **argv); /* handle */
+} cmd_ops_t;
+
+
+extern int engine_init(int comc, cmd_ops_t *comv, int argc, char **argv,
+ int *is_batch_mode);
+extern int engine_fini();
+
+extern int run_engine(int argc, char **argv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IDMAP_ENGINE_H */
diff --git a/usr/src/cmd/idmap/idmapd/Makefile b/usr/src/cmd/idmap/idmapd/Makefile
new file mode 100644
index 0000000000..9a68a226c3
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/Makefile
@@ -0,0 +1,109 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG = idmapd
+MANIFEST = idmap.xml
+SERVEROBJS = idmapd.o init.o dbutils.o rpc_svc.o server.o adutils.o \
+ idmap_config.o
+SERVERSRCS = $(SERVEROBJS:%.o=%.c)
+OBJS = $(SERVEROBJS)
+SRCS = $(SERVERSRCS)
+POFILES = $(OBJS:%.o=%.po)
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+
+LIBSQLITE = $(ROOT)/usr/lib/libsqlite.o
+SQLITELINT = $(ROOT)/usr/lib/llib-lsqlite.ln
+
+IDMAP_PROT_DIR = $(SRC)/head/rpcsvc
+IDMAP_PROT_X = $(IDMAP_PROT_DIR)/idmap_prot.x
+IDMAP_PROT_H = $(IDMAP_PROT_DIR)/idmap_prot.h
+
+include ../../Makefile.cmd
+
+POFILE = $(PROG)_all.po
+
+ROOTMANIFESTDIR = $(ROOTSVCSYSTEM)
+$(ROOTMANIFEST) := FILEMODE= 444
+
+INCS += -I. -I../../../lib/libidmap/common -I$(IDMAP_PROT_DIR)
+
+$(OBJS) := CPPFLAGS += $(INCS) -D_REENTRANT
+$(POFILE) := CPPFLAGS += $(INCS)
+CLOBBERFILES += $(IDMAP_PROT_H)
+
+CFLAGS += -v
+LDLIBS += -lsecdb -lnsl -lidmap -lscf -lldap
+
+$(PROG) := MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB)
+$(PROG) := LDFLAGS += $(MAPFILES:%=-M%)
+
+DIRMODE = 0755
+FILEMODE = 0555
+OWNER = root
+GROUP = sys
+
+lint_SRCS := CPPFLAGS += $(INCS) -D_REENTRANT
+lint := LDLIBS += $(SQLITELINT)
+
+.KEEP_STATE:
+
+.PARALLEL: $(OBJS)
+
+all: $(PROG)
+
+$(IDMAP_PROT_H): $(IDMAP_PROT_X)
+ $(RM) $@; $(RPCGEN) -CMNh -o $@ $(IDMAP_PROT_X)
+
+$(PROG): $(IDMAP_PROT_H) $(OBJS) $$(MAPFILES)
+ $(LINK.c) -o $@ $(OBJS) $(LIBSQLITE) $(LDLIBS)
+ $(POST_PROCESS)
+
+$(POFILE): $(POFILES)
+ $(RM) $(POFILE)
+ cat $(POFILES) > $(POFILE)
+
+install: all $(ROOTLIBPROG) $(ROOTMANIFEST)
+
+check: $(CHKMANIFEST)
+
+clean:
+ $(RM) $(OBJS)
+
+clobber:
+
+lint: lint_SRCS
+
+lint_SRCS:
+
+include ../../Makefile.targ
+
+FRC:
+
diff --git a/usr/src/cmd/idmap/idmapd/adutils.c b/usr/src/cmd/idmap/idmapd/adutils.c
new file mode 100644
index 0000000000..544eba857a
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/adutils.c
@@ -0,0 +1,1493 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Processes name2sid & sid2name batched lookups for a given user or
+ * computer from an AD Directory server using GSSAPI authentication
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <string.h>
+#include <strings.h>
+#include <lber.h>
+#include <ldap.h>
+#include <sasl/sasl.h>
+#include <string.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <synch.h>
+#include <atomic.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+#include "idmapd.h"
+
+/*
+ * Internal data structures for this code
+ */
+
+/* Attribute names and filter format strings */
+#define OBJECTSID "objectSid"
+#define OBJECTSIDFILTER "(objectSid=%s)"
+#define SAMACCOUNTNAME "sAMAccountName"
+#define SANFILTER "(sAMAccountName=%.*s)"
+#define OBJECTCLASS "objectClass"
+
+/*
+ * This should really be in some <sys/sid.h> file or so; we have a
+ * private version of sid_t, and so must other components of ON until we
+ * rationalize this.
+ */
+typedef struct sid {
+ uchar_t version;
+ uchar_t sub_authority_count;
+ uint64_t authority; /* really, 48-bits */
+ rid_t sub_authorities[SID_MAX_SUB_AUTHORITIES];
+} sid_t;
+
+/* A single DS */
+typedef struct ad_host {
+ struct ad_host *next;
+ ad_t *owner; /* ad_t to which this belongs */
+ pthread_mutex_t lock;
+ LDAP *ld; /* LDAP connection */
+ uint32_t ref; /* ref count */
+ time_t idletime; /* time since last activity */
+ int dead; /* error on LDAP connection */
+ /*
+ * Used to distinguish between different instances of LDAP
+ * connections to this same DS. We need this so we never mix up
+ * results for a given msgID from one connection with those of
+ * another earlier connection where two batch state structures
+ * share this ad_host object but used different LDAP connections
+ * to send their LDAP searches.
+ */
+ uint64_t generation;
+
+ /* LDAP DS info */
+ char *host;
+ int port;
+
+ /* hardwired to SASL GSSAPI only for now */
+ char *saslmech;
+ unsigned saslflags;
+} ad_host_t;
+
+/* A set of DSs for a given AD partition; ad_t typedef comes from adutil.h */
+struct ad {
+ char *dflt_w2k_dom; /* used to qualify bare names */
+ char *basedn; /* derived from dflt domain */
+ pthread_mutex_t lock;
+ uint32_t ref;
+ idmap_ad_partition_t partition; /* Data or global catalog? */
+};
+
+/*
+ * A place to put the results of a batched (async) query
+ *
+ * There is one of these for every query added to a batch object
+ * (idmap_query_state, see below).
+ */
+typedef struct idmap_q {
+ char **result; /* name or stringified SID */
+ char **domain; /* name of domain of object */
+ rid_t *rid; /* for n2s, if not NULL */
+ int *sid_type; /* if not NULL */
+ idmap_retcode *rc;
+ int msgid; /* LDAP message ID */
+ /*
+ * Bitfield containing state needed to know when we're done
+ * processing search results related to this query's LDAP
+ * searches. Mostly self-explanatory.
+ */
+ uint16_t n2s : 1; /* name->SID or SID->name? */
+ uint16_t got_reply : 1;
+ uint16_t got_results : 1;
+ uint16_t got_objectSid : 1;
+ uint16_t got_objectClass : 1;
+ uint16_t got_samAcctName : 1;
+} idmap_q_t;
+
+/* Batch context structure; typedef is in header file */
+struct idmap_query_state {
+ idmap_query_state_t *next;
+ int qcount; /* how many queries */
+ uint32_t qlastsent;
+ uint32_t qinflight; /* how many queries in flight */
+ uint16_t qdead; /* oops, lost LDAP connection */
+ ad_host_t *qadh; /* LDAP connection */
+ uint64_t qadh_gen; /* same as qadh->generation */
+ idmap_q_t queries[1]; /* array of query results */
+};
+
+/*
+ * List of query state structs -- needed so we can "route" LDAP results
+ * to the right context if multiple threads should be using the same
+ * connection concurrently
+ */
+static idmap_query_state_t *qstatehead = NULL;
+static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * List of DSs, needed by the idle connection reaper thread
+ */
+static ad_host_t *host_head = NULL;
+static pthread_t reaperid = (pthread_t)-1;
+static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER;
+
+/*ARGSUSED*/
+static int
+idmap_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) {
+ sasl_interact_t *interact;
+
+ if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
+ return (LDAP_PARAM_ERROR);
+
+ /* There should be no extra arguemnts for SASL/GSSAPI authentication */
+ for (interact = prompts; interact->id != SASL_CB_LIST_END;
+ interact++) {
+ interact->result = NULL;
+ interact->len = 0;
+ }
+ return (LDAP_SUCCESS);
+}
+
+/* Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" */
+static
+char *
+dns2dn(const char *dns)
+{
+ int nameparts;
+
+ /* Sigh, ldap_dns_to_dn()'s first arg should be a const char * */
+ return (ldap_dns_to_dn((char *)dns, &nameparts));
+}
+
+/*
+ * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other
+ * attributes (CN, etc...)
+ */
+static
+char *
+dn2dns(const char *dn)
+{
+ char **rdns = NULL;
+ char **attrs = NULL;
+ char **labels = NULL;
+ char *dns = NULL;
+ char **rdn, **attr, **label;
+ int maxlabels = 5;
+ int nlabels = 0;
+ int dnslen;
+
+ /*
+ * There is no reverse of ldap_dns_to_dn() in our libldap, so we
+ * have to do the hard work here for now.
+ */
+
+ /*
+ * This code is much too liberal: it looks for "dc" attributes
+ * in all RDNs of the DN. In theory this could cause problems
+ * if people were to use "dc" in nodes other than the root of
+ * the tree, but in practice noone, least of all Active
+ * Directory, does that.
+ *
+ * On the other hand, this code is much too conservative: it
+ * does not make assumptions about ldap_explode_dn(), and _that_
+ * is the true for looking at every attr of every RDN.
+ *
+ * Since we only ever look at dc and those must be DNS labels,
+ * at least until we get around to supporting IDN here we
+ * shouldn't see escaped labels from AD nor from libldap, though
+ * the spec (RFC2253) does allow libldap to escape things that
+ * don't need escaping -- if that should ever happen then
+ * libldap will need a spanking, and we can take care of that.
+ */
+
+ /* Explode a DN into RDNs */
+ if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
+ return (NULL);
+
+ labels = calloc(maxlabels + 1, sizeof (char *));
+ label = labels;
+
+ for (rdn = rdns; *rdn != NULL; rdn++) {
+ if (attrs != NULL)
+ ldap_value_free(attrs);
+
+ /* Explode each RDN, look for DC attr, save val as DNS label */
+ if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL)
+ goto done;
+
+ for (attr = attrs; *attr != NULL; attr++) {
+ if (strncasecmp(*attr, "dc=", 3) != 0)
+ continue;
+
+ /* Found a DNS label */
+ labels[nlabels++] = strdup((*attr) + 3);
+
+ if (nlabels == maxlabels) {
+ char **tmp;
+ tmp = realloc(labels,
+ sizeof (char *) * (maxlabels + 1));
+
+ if (tmp == NULL)
+ goto done;
+
+ labels = tmp;
+ labels[nlabels] = NULL;
+ }
+
+ /* There should be just one DC= attr per-RDN */
+ break;
+ }
+ }
+
+ /*
+ * Got all the labels, now join with '.'
+ *
+ * We need room for nlabels - 1 periods ('.'), one nul
+ * terminator, and the strlen() of each label.
+ */
+ dnslen = nlabels;
+ for (label = labels; *label != NULL; label++)
+ dnslen += strlen(*label);
+
+ if ((dns = malloc(dnslen)) == NULL)
+ goto done;
+
+ *dns = '\0';
+
+ for (label = labels; *label != NULL; label++) {
+ (void) strlcat(dns, *label, dnslen);
+ /*
+ * NOTE: the last '.' won't be appended -- there's no room
+ * for it!
+ */
+ (void) strlcat(dns, ".", dnslen);
+ }
+
+done:
+ if (labels != NULL) {
+ for (label = labels; *label != NULL; label++)
+ free(*label);
+ free(labels);
+ }
+ if (attrs != NULL)
+ ldap_value_free(attrs);
+ if (rdns != NULL)
+ ldap_value_free(rdns);
+
+ return (dns);
+}
+
+/*
+ * Keep connection management simple for now, extend or replace later
+ * with updated libsldap code.
+ */
+#define ADREAPERSLEEP 60
+#define ADCONN_TIME 300
+
+/*
+ * Idle connection reaping side of connection management
+ *
+ * Every minute wake up and look for connections that have been idle for
+ * five minutes or more and close them.
+ */
+/*ARGSUSED*/
+static
+void
+adreaper(void *arg)
+{
+ ad_host_t *adh;
+ time_t now;
+ timespec_t ts;
+
+ ts.tv_sec = ADREAPERSLEEP;
+ ts.tv_nsec = 0;
+
+ for (;;) {
+ /*
+ * nanosleep(3RT) is thead-safe (no SIGALRM) and more
+ * portable than usleep(3C)
+ */
+ (void) nanosleep(&ts, NULL);
+ (void) pthread_mutex_lock(&adhostlock);
+ now = time(NULL);
+ for (adh = host_head; adh != NULL; adh = adh->next) {
+ (void) pthread_mutex_lock(&adh->lock);
+ if (adh->ref == 0 && adh->idletime != 0 &&
+ adh->idletime + ADCONN_TIME < now) {
+ if (adh->ld) {
+ (void) ldap_unbind(adh->ld);
+ adh->ld = NULL;
+ adh->idletime = 0;
+ adh->ref = 0;
+ }
+ }
+ (void) pthread_mutex_unlock(&adh->lock);
+ }
+ (void) pthread_mutex_unlock(&adhostlock);
+ }
+}
+
+int
+idmap_ad_alloc(ad_t **new_ad, const char *default_domain,
+ idmap_ad_partition_t part)
+{
+ ad_t *ad;
+
+ *new_ad = NULL;
+
+ if ((default_domain == NULL || *default_domain == '\0') &&
+ part != IDMAP_AD_GLOBAL_CATALOG)
+ return (-1);
+
+ if ((ad = calloc(1, sizeof (ad_t))) == NULL)
+ return (-1);
+
+ ad->ref = 1;
+ ad->partition = part;
+
+ /*
+ * If default_domain is NULL, deal, deferring errors until
+ * idmap_lookup_batch_start() -- this makes it easier on the
+ * caller, who can simply observe lookups failing as opposed to
+ * having to conditionalize calls to lookups according to
+ * whether it has a non-NULL ad_t *.
+ */
+ if (default_domain == NULL)
+ default_domain = "";
+
+ if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL)
+ goto err;
+
+ /* If default_domain is empty, deal; see above */
+ if (*default_domain == '\0') {
+ if ((ad->basedn = strdup("")) == NULL)
+ goto err;
+ } else if ((ad->basedn = dns2dn(default_domain)) == NULL) {
+ goto err;
+ }
+
+ if (pthread_mutex_init(&ad->lock, NULL) != 0)
+ goto err;
+
+ *new_ad = ad;
+
+ return (0);
+err:
+ if (ad->dflt_w2k_dom != NULL)
+ free(ad->dflt_w2k_dom);
+ if (ad->basedn != NULL)
+ free(ad->basedn);
+ free(ad);
+ return (-1);
+}
+
+
+void
+idmap_ad_free(ad_t **ad)
+{
+ ad_host_t *p;
+
+ if (ad == NULL || *ad == NULL)
+ return;
+
+ (void) pthread_mutex_lock(&(*ad)->lock);
+
+ if (atomic_dec_32_nv(&(*ad)->ref) > 0) {
+ (void) pthread_mutex_unlock(&(*ad)->lock);
+ *ad = NULL;
+ return;
+ }
+
+ for (p = host_head; p != NULL; p = p->next) {
+ if (p->owner != (*ad))
+ continue;
+ idmap_delete_ds((*ad), p->host, p->port);
+ }
+
+ free((*ad)->basedn);
+
+ (void) pthread_mutex_unlock(&(*ad)->lock);
+ (void) pthread_mutex_destroy(&(*ad)->lock);
+
+ free(*ad);
+
+ *ad = NULL;
+}
+
+static
+int
+idmap_open_conn(ad_host_t *adh)
+{
+ int rc, ldversion;
+
+ if (adh->dead && adh->ld != NULL) {
+ (void) ldap_unbind(adh->ld);
+ adh->ld = NULL;
+ adh->dead = 0;
+ }
+
+ if (adh->ld == NULL) {
+ int zero = 0;
+ int timeoutms = 30 * 1000;
+
+ atomic_inc_64(&adh->generation);
+ adh->ld = ldap_init(adh->host, adh->port);
+ if (adh->ld == NULL)
+ return (-1);
+
+ ldversion = LDAP_VERSION3;
+ (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION,
+ &ldversion);
+
+ (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS,
+ LDAP_OPT_OFF);
+ (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero);
+ (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero);
+ /* setup TCP/IP connect timeout */
+ (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT,
+ &timeoutms);
+ (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
+ rc = ldap_sasl_interactive_bind_s(adh->ld,
+ "" /* binddn */, adh->saslmech, NULL, NULL, adh->saslflags,
+ &idmap_saslcallback, NULL /* defaults */);
+
+ if (rc != LDAP_SUCCESS) {
+ idmapdlog(LOG_ERR, "Could not authenticate to the "
+ "LDAP server. (Check that the host keys are "
+ "correct?)");
+ return (rc);
+ }
+ }
+
+ adh->idletime = time(NULL);
+
+ return (LDAP_SUCCESS);
+}
+
+
+/*
+ * Connection management: find an open connection or open one
+ */
+static
+ad_host_t *
+idmap_get_conn(const ad_t *ad)
+{
+ ad_host_t *adh = NULL;
+ int rc;
+
+ (void) pthread_mutex_lock(&adhostlock);
+
+ /*
+ * Search for any ad_host_t, preferably one with an open
+ * connection
+ */
+ for (adh = host_head; adh != NULL; adh = adh->next) {
+ if (adh->owner == ad) {
+ break;
+ }
+ }
+
+ if (adh != NULL)
+ atomic_inc_32(&adh->ref);
+
+ (void) pthread_mutex_unlock(&adhostlock);
+
+ if (adh == NULL)
+ return (NULL);
+
+ /* found connection, open it if not opened */
+ (void) pthread_mutex_lock(&adh->lock);
+ rc = idmap_open_conn(adh);
+ (void) pthread_mutex_unlock(&adh->lock);
+ if (rc != LDAP_SUCCESS)
+ return (NULL);
+
+ return (adh);
+}
+
+static
+void
+idmap_release_conn(ad_host_t *adh)
+{
+ (void) pthread_mutex_lock(&adh->lock);
+ if (atomic_dec_32_nv(&adh->ref) == 0)
+ adh->idletime = time(NULL);
+ (void) pthread_mutex_unlock(&adh->lock);
+}
+
+/*
+ * Take ad_host_config_t information, create a ad_host_t,
+ * populate it and add it to the list of hosts.
+ */
+
+int
+idmap_add_ds(ad_t *ad, const char *host, int port)
+{
+ ad_host_t *p;
+ ad_host_t *new = NULL;
+ int ret = -1;
+
+ if (port == 0)
+ port = (int)ad->partition;
+
+ (void) pthread_mutex_lock(&adhostlock);
+ for (p = host_head; p != NULL; p = p->next) {
+ if (p->owner != ad)
+ continue;
+
+ if (strcmp(host, p->host) == 0 && p->port == port) {
+ /* already added */
+ ret = -2;
+ goto err;
+ }
+ }
+
+ /* add new entry */
+ new = (ad_host_t *)calloc(1, sizeof (ad_host_t));
+ if (new == NULL)
+ goto err;
+ new->owner = ad;
+ new->port = port;
+ new->dead = 0;
+ if ((new->host = strdup(host)) == NULL)
+ goto err;
+
+ /* default to SASL GSSAPI only for now */
+ new->saslflags = LDAP_SASL_INTERACTIVE;
+ new->saslmech = "GSSAPI";
+
+ if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) {
+ free(new->host);
+ new->host = NULL;
+ errno = ret;
+ ret = -1;
+ goto err;
+ }
+
+ /* link in */
+ new->next = host_head;
+ host_head = new;
+
+ /* Start reaper if it doesn't exist */
+ if (reaperid == 0)
+ (void) pthread_create(&reaperid, NULL,
+ (void *(*)(void *))adreaper, (void *)NULL);
+
+err:
+ (void) pthread_mutex_unlock(&adhostlock);
+
+ if (ret != 0 && new != NULL) {
+ if (new->host != NULL) {
+ (void) pthread_mutex_destroy(&new->lock);
+ free(new->host);
+ }
+ free(new);
+ }
+
+ return (ret);
+}
+
+/*
+ * free a DS configuration
+ */
+void
+idmap_delete_ds(ad_t *ad, const char *host, int port)
+{
+ ad_host_t **p, *q;
+
+ (void) pthread_mutex_lock(&adhostlock);
+ for (p = &host_head; *p != NULL; p = &((*p)->next)) {
+ if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 ||
+ (*p)->port != port)
+ continue;
+ /* found */
+ if (atomic_dec_32_nv(&((*p)->ref)) > 0)
+ break; /* still in use */
+
+ q = *p;
+ *p = (*p)->next;
+
+ (void) pthread_mutex_destroy(&q->lock);
+
+ if (q->ld)
+ (void) ldap_unbind(q->ld);
+ if (q->host)
+ free(q->host);
+ free(q);
+ break;
+ }
+ (void) pthread_mutex_unlock(&adhostlock);
+}
+
+/*
+ * Convert a binary SID in a BerValue to a sid_t
+ */
+static
+int
+idmap_getsid(BerValue *bval, sid_t *sidp)
+{
+ int i, j;
+ uchar_t *v;
+ uint32_t a;
+
+ /*
+ * The binary format of a SID is as follows:
+ *
+ * byte #0: version, always 0x01
+ * byte #1: RID count, always <= 0x0f
+ * bytes #2-#7: SID authority, big-endian 48-bit unsigned int
+ *
+ * followed by RID count RIDs, each a little-endian, unsigned
+ * 32-bit int.
+ */
+ /*
+ * Sanity checks: must have at least one RID, version must be
+ * 0x01, and the length must be 8 + rid count * 4
+ */
+ if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 &&
+ bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) {
+ v = (uchar_t *)bval->bv_val;
+ sidp->version = v[0];
+ sidp->sub_authority_count = v[1];
+ sidp->authority =
+ /* big endian -- so start from the left */
+ ((u_longlong_t)v[2] << 40) |
+ ((u_longlong_t)v[3] << 32) |
+ ((u_longlong_t)v[4] << 24) |
+ ((u_longlong_t)v[5] << 16) |
+ ((u_longlong_t)v[6] << 8) |
+ (u_longlong_t)v[7];
+ for (i = 0; i < sidp->sub_authority_count; i++) {
+ j = 8 + (i * 4);
+ /* little endian -- so start from the right */
+ a = (v[j + 3] << 24) | (v[j + 2] << 16) |
+ (v[j + 1] << 8) | (v[j]);
+ sidp->sub_authorities[i] = a;
+ }
+ return (0);
+ }
+ return (-1);
+}
+
+/*
+ * Convert a sid_t to S-1-...
+ */
+static
+char *
+idmap_sid2txt(sid_t *sidp)
+{
+ int rlen, i, len;
+ char *str, *cp;
+
+ if (sidp->version != 1)
+ return (NULL);
+
+ len = sizeof ("S-1-") - 1;
+
+ /*
+ * We could optimize like so, but, why?
+ * if (sidp->authority < 10)
+ * len += 2;
+ * else if (sidp->authority < 100)
+ * len += 3;
+ * else
+ * len += snprintf(NULL, 0"%llu", sidp->authority);
+ */
+ len += snprintf(NULL, 0, "%llu", sidp->authority);
+
+ /* Max length of a uint32_t printed out in ASCII is 10 bytes */
+ len += 1 + (sidp->sub_authority_count + 1) * 10;
+
+ if ((cp = str = malloc(len)) == NULL)
+ return (NULL);
+
+ rlen = snprintf(str, len, "S-1-%llu", sidp->authority);
+
+ cp += rlen;
+ len -= rlen;
+
+ for (i = 0; i < sidp->sub_authority_count; i++) {
+ assert(len > 0);
+ rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]);
+ cp += rlen;
+ len -= rlen;
+ assert(len >= 0);
+ }
+
+ return (str);
+}
+
+/*
+ * Convert a sid_t to on-the-wire encoding
+ */
+static
+int
+idmap_sid2binsid(sid_t *sid, uchar_t *binsid, int binsidlen)
+{
+ uchar_t *p;
+ int i;
+ uint64_t a;
+ uint32_t r;
+
+ if (sid->version != 1 ||
+ binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4))
+ return (-1);
+
+ p = binsid;
+ *p++ = 0x01; /* version */
+ /* sub authority count */
+ *p++ = sid->sub_authority_count;
+ /* Authority */
+ a = sid->authority;
+ /* big-endian -- start from left */
+ *p++ = (a >> 40) & 0xFF;
+ *p++ = (a >> 32) & 0xFF;
+ *p++ = (a >> 24) & 0xFF;
+ *p++ = (a >> 16) & 0xFF;
+ *p++ = (a >> 8) & 0xFF;
+ *p++ = a & 0xFF;
+
+ /* sub-authorities */
+ for (i = 0; i < sid->sub_authority_count; i++) {
+ r = sid->sub_authorities[i];
+ /* little-endian -- start from right */
+ *p++ = (r & 0x000000FF);
+ *p++ = (r & 0x0000FF00) >> 8;
+ *p++ = (r & 0x00FF0000) >> 16;
+ *p++ = (r & 0xFF000000) >> 24;
+ }
+
+ return (0);
+}
+
+/*
+ * Convert a stringified SID (S-1-...) into a hex-encoded version of the
+ * on-the-wire encoding, but with each pair of hex digits pre-pended
+ * with a '\', so we can pass this to libldap.
+ */
+static
+int
+idmap_txtsid2hexbinsid(const char *txt, const rid_t *rid,
+ char *hexbinsid, int hexbinsidlen)
+{
+ sid_t sid = { 0 };
+ int i, j;
+ const char *cp;
+ char *ecp;
+ u_longlong_t a;
+ unsigned long r;
+ uchar_t *binsid, b, hb;
+
+ /* Only version 1 SIDs please */
+ if (strncmp(txt, "S-1-", strlen("S-1-")) != 0)
+ return (-1);
+
+ if (strlen(txt) < (strlen("S-1-") + 1))
+ return (-1);
+
+ /* count '-'s */
+ for (j = 0, cp = strchr(txt, '-');
+ cp != NULL && *cp != '\0';
+ j++, cp = strchr(cp + 1, '-')) {
+ /* can't end on a '-' */
+ if (*(cp + 1) == '\0')
+ return (-1);
+ }
+
+ /* must have at least one RID, but not too many */
+ if (j < 3 || (j - 1) > SID_MAX_SUB_AUTHORITIES ||
+ (rid != NULL && j > SID_MAX_SUB_AUTHORITIES))
+ return (-1);
+
+ /* check that we only have digits and '-' */
+ if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1))
+ return (-1);
+
+ /* we know the version number and RID count */
+ sid.version = 1;
+ sid.sub_authority_count = j - 2;
+
+ cp = txt + strlen("S-1-");
+
+ /* 64-bit safe parsing of unsigned 48-bit authority value */
+ errno = 0;
+ a = strtoull(cp, &ecp, 10);
+
+ /* errors parsing the authority or too many bits */
+ if (cp == ecp || (a == 0 && errno == EINVAL) ||
+ (a == ULLONG_MAX && errno == ERANGE) ||
+ (a & 0x0000ffffffffffffULL) != a)
+ return (-1);
+
+ cp = ecp;
+
+ sid.authority = (uint64_t)a;
+
+ for (i = 0; i < sid.sub_authority_count; i++) {
+ if (*cp++ != '-')
+ return (-1);
+ /* 64-bit safe parsing of unsigned 32-bit RID */
+ errno = 0;
+ r = strtoul(cp, &ecp, 10);
+ /* errors parsing the RID or too many bits */
+ if (cp == ecp || (r == 0 && errno == EINVAL) ||
+ (r == ULONG_MAX && errno == ERANGE) ||
+ (r & 0xffffffffUL) != r)
+ return (-1);
+ sid.sub_authorities[i] = (uint32_t)r;
+ cp = ecp;
+ }
+
+ /* check that all of the string SID has been consumed */
+ if (*cp != '\0')
+ return (-1);
+
+ if (rid != NULL) {
+ sid.sub_authorities[sid.sub_authority_count++] = *rid;
+ }
+
+ j = 1 + 1 + 6 + sid.sub_authority_count * 4;
+
+ if (hexbinsidlen < (j * 3))
+ return (-2);
+
+ /* binary encode the SID */
+ binsid = (uchar_t *)alloca(j);
+ (void) idmap_sid2binsid(&sid, binsid, j);
+
+ /* hex encode, with a backslash before each byte */
+ for (ecp = hexbinsid, i = 0; i < j; i++) {
+ b = binsid[i];
+ *ecp++ = '\\';
+ hb = (b >> 4) & 0xF;
+ *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
+ hb = b & 0xF;
+ *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
+ }
+ *ecp = '\0';
+
+ return (0);
+}
+
+static
+char *
+convert_bval2sid(BerValue *bval, rid_t *rid)
+{
+ sid_t sid;
+
+ if (idmap_getsid(bval, &sid) < 0)
+ return (NULL);
+
+ /*
+ * If desired and if the SID is what should be a domain/computer
+ * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then
+ * save the last RID and truncate the SID
+ */
+ if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5)
+ *rid = sid.sub_authorities[--sid.sub_authority_count];
+ return (idmap_sid2txt(&sid));
+}
+
+
+idmap_retcode
+idmap_lookup_batch_start(ad_t *ad, int nqueries, idmap_query_state_t **state)
+{
+ idmap_query_state_t *new_state;
+ ad_host_t *adh = NULL;
+
+ *state = NULL;
+
+ if (*ad->dflt_w2k_dom == '\0')
+ return (-1);
+
+ adh = idmap_get_conn(ad);
+ if (adh == NULL)
+ return (IDMAP_ERR_OTHER);
+
+ new_state = calloc(1, sizeof (idmap_query_state_t) +
+ (nqueries - 1) * sizeof (idmap_q_t));
+
+ if (new_state == NULL)
+ return (IDMAP_ERR_MEMORY);
+
+ new_state->qadh = adh;
+ new_state->qcount = nqueries;
+ new_state->qadh_gen = adh->generation;
+ /* should be -1, but the atomic routines want unsigned */
+ new_state->qlastsent = 0;
+
+ (void) pthread_mutex_lock(&qstatelock);
+ new_state->next = qstatehead;
+ qstatehead = new_state;
+ (void) pthread_mutex_unlock(&qstatelock);
+
+ *state = new_state;
+
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * Find the idmap_query_state_t to which a given LDAP result msgid on a
+ * given connection belongs
+ */
+static
+int
+idmap_msgid2query(ad_host_t *adh, int msgid,
+ idmap_query_state_t **state, int *qid)
+{
+ idmap_query_state_t *p;
+ int i;
+
+ (void) pthread_mutex_lock(&qstatelock);
+ for (p = qstatehead; p != NULL; p = p->next) {
+ if (p->qadh != adh || adh->generation != p->qadh_gen)
+ continue;
+ for (i = 0; i < p->qcount; i++) {
+ if ((p->queries[i]).msgid == msgid) {
+ *state = p;
+ *qid = i;
+ (void) pthread_mutex_unlock(&qstatelock);
+ return (1);
+ }
+ }
+ }
+ (void) pthread_mutex_unlock(&qstatelock);
+ return (0);
+}
+
+/*
+ * Handle an objectSid attr from a result
+ */
+static
+void
+idmap_bv_objsid2sidstr(BerValue **bvalues, idmap_q_t *q)
+{
+ if (bvalues == NULL)
+ return;
+ /* objectSid is single valued */
+ *(q->result) = convert_bval2sid(bvalues[0], q->rid);
+ q->got_objectSid = 1;
+}
+
+/*
+ * Handle a sAMAccountName attr from a result
+ */
+static
+void
+idmap_bv_samaccountname2name(BerValue **bvalues, idmap_q_t *q, const char *dn)
+{
+ char *result, *domain;
+ int len;
+
+ if (bvalues == NULL)
+ return;
+
+ if ((domain = dn2dns(dn)) == NULL)
+ return;
+
+ if (bvalues == NULL || bvalues[0] == NULL ||
+ bvalues[0]->bv_val == NULL)
+ return;
+
+ len = bvalues[0]->bv_len + 1;
+
+ if (q->domain != NULL)
+ *(q->domain) = domain;
+ else
+ len += strlen(domain) + 1;
+
+ if ((result = malloc(len)) == NULL) {
+ if (q->domain != NULL)
+ *(q->domain) = NULL;
+ free(domain);
+ return;
+ }
+
+ (void) memcpy(result, bvalues[0]->bv_val, (size_t)bvalues[0]->bv_len);
+ result[bvalues[0]->bv_len] = '\0';
+
+ if (q->domain == NULL) {
+ (void) strlcat(result, "@", len);
+ (void) strlcat(result, domain, len);
+ free(domain);
+ }
+
+ *(q->result) = result;
+ q->got_samAcctName = 1;
+}
+
+
+#define BVAL_CASEEQ(bv, str) \
+ (((*(bv))->bv_len == (sizeof (str) - 1)) && \
+ strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0)
+
+/*
+ * Handle an objectClass attr from a result
+ */
+static
+void
+idmap_bv_objclass2sidtype(BerValue **bvalues, idmap_q_t *q)
+{
+ BerValue **cbval;
+
+ if (bvalues == NULL)
+ return;
+
+ for (cbval = bvalues; *cbval != NULL; cbval++) {
+ /* don't clobber sid_type */
+ if (*(q->sid_type) == _IDMAP_T_COMPUTER ||
+ *(q->sid_type) == _IDMAP_T_GROUP ||
+ *(q->sid_type) == _IDMAP_T_USER)
+ continue;
+
+ if (BVAL_CASEEQ(cbval, "Computer")) {
+ *(q->sid_type) = _IDMAP_T_COMPUTER;
+ return;
+ } else if (BVAL_CASEEQ(cbval, "Group")) {
+ *(q->sid_type) = _IDMAP_T_GROUP;
+ } else if (BVAL_CASEEQ(cbval, "USER")) {
+ *(q->sid_type) = _IDMAP_T_USER;
+ } else
+ *(q->sid_type) = _IDMAP_T_OTHER;
+ q->got_objectClass = 1;
+ }
+}
+
+/*
+ * Handle a given search result entry
+ */
+static
+void
+idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res)
+{
+ char *dn, *attr;
+ BerElement *ber = NULL;
+ BerValue **bvalues;
+ ad_host_t *adh;
+ idmap_q_t *q;
+ idmap_retcode orc;
+
+ adh = state->qadh;
+
+ (void) pthread_mutex_lock(&adh->lock);
+
+ if (adh->dead || (dn = ldap_get_dn(adh->ld, res)) == NULL) {
+ (void) pthread_mutex_unlock(&adh->lock);
+ return;
+ }
+
+ q = &(state->queries[qid]);
+
+ for (attr = ldap_first_attribute(adh->ld, res, &ber); attr != NULL;
+ attr = ldap_next_attribute(adh->ld, res, ber)) {
+ orc = *q->rc;
+ bvalues = NULL; /* for memory management below */
+
+ /*
+ * If this is an attribute we are looking for and
+ * haven't seen it yet, parse it
+ */
+ if (orc != IDMAP_SUCCESS && q->n2s && !q->got_objectSid &&
+ strcasecmp(attr, OBJECTSID) == 0) {
+ bvalues = ldap_get_values_len(adh->ld, res, attr);
+ idmap_bv_objsid2sidstr(bvalues, q);
+ } else if (orc != IDMAP_SUCCESS && !q->n2s &&
+ !q->got_samAcctName &&
+ strcasecmp(attr, SAMACCOUNTNAME) == 0) {
+ bvalues = ldap_get_values_len(adh->ld, res, attr);
+ idmap_bv_samaccountname2name(bvalues, q, dn);
+ } else if (orc != IDMAP_SUCCESS && !q->got_objectClass &&
+ strcasecmp(attr, OBJECTCLASS) == 0) {
+ bvalues = ldap_get_values_len(adh->ld, res, attr);
+ idmap_bv_objclass2sidtype(bvalues, q);
+ }
+
+ if (bvalues != NULL)
+ ldap_value_free_len(bvalues);
+ ldap_memfree(attr);
+
+ if (q->n2s)
+ *q->rc = (q->got_objectSid &&
+ q->got_objectClass) ?
+ IDMAP_SUCCESS : IDMAP_ERR_NORESULT;
+ else
+ *q->rc = (q->got_samAcctName &&
+ q->got_objectClass) ?
+ IDMAP_SUCCESS : IDMAP_ERR_NORESULT;
+
+ if (*q->rc == IDMAP_SUCCESS && *q->result == NULL)
+ *q->rc = IDMAP_ERR_NORESULT;
+ }
+ (void) pthread_mutex_unlock(&adh->lock);
+
+ /*
+ * If there should be multiple partial results for different
+ * entities (there should not be, but, if it should happen) then
+ * it's possible that they could get mixed up here and we could
+ * get bogus results. We just mark the query's results as
+ * toxic (IDMAP_ERR_INTERNAL).
+ *
+ * Between this and ignoring results when we've already filled
+ * out a query's results we should be OK. The first full reply
+ * wins. In practice we should never get multiple results.
+ */
+ if (orc == IDMAP_ERR_INTERNAL)
+ *q->rc = IDMAP_ERR_INTERNAL;
+ else if (*q->rc != IDMAP_SUCCESS)
+ *q->rc = IDMAP_ERR_INTERNAL;
+
+ if (ber != NULL)
+ ber_free(ber, 0);
+
+ ldap_memfree(dn);
+}
+
+/*
+ * Try to get a result; if there is one, find the corresponding
+ * idmap_q_t and process the result.
+ */
+static
+int
+idmap_get_adobject_batch(ad_host_t *adh, struct timeval *timeout)
+{
+ idmap_query_state_t *query_state;
+ LDAPMessage *res = NULL;
+ int rc, ret, msgid, qid;
+
+ (void) pthread_mutex_lock(&adh->lock);
+ if (adh->dead) {
+ (void) pthread_mutex_unlock(&adh->lock);
+ return (-1);
+ }
+
+ /* Get one result */
+ rc = ldap_result(adh->ld, LDAP_RES_ANY, 0,
+ timeout, &res);
+ if (rc == LDAP_UNAVAILABLE || rc == LDAP_UNWILLING_TO_PERFORM ||
+ rc == LDAP_CONNECT_ERROR || rc == LDAP_SERVER_DOWN ||
+ rc == LDAP_BUSY)
+ adh->dead = 1;
+ (void) pthread_mutex_unlock(&adh->lock);
+
+ if (adh->dead)
+ return (-1);
+
+ switch (rc) {
+ case LDAP_RES_SEARCH_RESULT:
+ /* We have all the LDAP replies for some search... */
+ msgid = ldap_msgid(res);
+ if (idmap_msgid2query(adh, msgid,
+ &query_state, &qid)) {
+ /* ...so we can decrement qinflight */
+ atomic_dec_32(&query_state->qinflight);
+ /* we saw at least one reply */
+ query_state->queries[qid].got_reply = 1;
+ }
+ (void) ldap_msgfree(res);
+ ret = 0;
+ break;
+ case LDAP_RES_SEARCH_REFERENCE:
+ /*
+ * We have no need for these at the moment. Eventually,
+ * when we query things that we can't expect to find in
+ * the Global Catalog then we'll need to learn to follow
+ * references.
+ */
+ (void) ldap_msgfree(res);
+ ret = 0;
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ /* Got a result */
+ msgid = ldap_msgid(res);
+ if (idmap_msgid2query(adh, msgid,
+ &query_state, &qid)) {
+ idmap_extract_object(query_state, qid, res);
+ /* we saw at least one result */
+ query_state->queries[qid].got_reply = 1;
+ query_state->queries[qid].got_results = 1;
+ }
+ (void) ldap_msgfree(res);
+ ret = 0;
+ break;
+ default:
+ /* timeout or error; treat the same */
+ ret = -1;
+ break;
+ }
+
+ return (ret);
+}
+
+void
+idmap_lookup_free_batch(idmap_query_state_t **state)
+{
+ idmap_query_state_t **p;
+
+ idmap_release_conn((*state)->qadh);
+
+ /* Remove this state struct from the list of state structs */
+ (void) pthread_mutex_lock(&qstatelock);
+ for (p = &qstatehead; *p != NULL; p = &(*p)->next) {
+ if (*p == (*state)) {
+ *p = (*state)->next;
+ break;
+ }
+ }
+ (void) pthread_mutex_unlock(&qstatelock);
+
+ free(*state);
+ *state = NULL;
+}
+
+idmap_retcode
+idmap_lookup_batch_end(idmap_query_state_t **state,
+ struct timeval *timeout)
+{
+ idmap_q_t *q;
+ int i;
+ int rc = LDAP_SUCCESS;
+ idmap_retcode retcode = IDMAP_SUCCESS;
+
+ (*state)->qdead = 1;
+
+ /* Process results until done or until timeout, if given */
+ while ((*state)->qinflight > 0) {
+ if ((rc = idmap_get_adobject_batch((*state)->qadh,
+ timeout)) != 0)
+ break;
+ }
+
+ if (rc == LDAP_UNAVAILABLE || rc == LDAP_UNWILLING_TO_PERFORM ||
+ rc == LDAP_CONNECT_ERROR || rc == LDAP_SERVER_DOWN ||
+ rc == LDAP_BUSY) {
+ retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
+ (*state)->qadh->dead = 1;
+ }
+
+ for (i = 0; i < (*state)->qcount; i++) {
+ q = &((*state)->queries[i]);
+ if (q->got_reply && !q->got_results) {
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
+ *q->rc = IDMAP_ERR_RETRIABLE_NET_ERR;
+ else
+ *q->rc = IDMAP_ERR_NOTFOUND;
+ }
+ }
+
+ idmap_lookup_free_batch(state);
+
+ return (retcode);
+}
+
+/*
+ * Send one prepared search, queue up msgid, process what results are
+ * available
+ */
+static
+idmap_retcode
+idmap_batch_add1(idmap_query_state_t *state, int n2s,
+ const char *filter, const char *basedn,
+ char **result, char **dname, rid_t *rid, int *sid_type,
+ idmap_retcode *rc)
+{
+ idmap_retcode retcode = IDMAP_SUCCESS;
+ int lrc, qid;
+ struct timeval tv;
+ idmap_q_t *q;
+
+ if (state->qdead) {
+ *rc = IDMAP_ERR_NORESULT;
+ return (IDMAP_ERR_RETRIABLE_NET_ERR);
+ }
+
+ qid = atomic_inc_32_nv(&state->qlastsent) - 1;
+
+ q = &(state->queries[qid]);
+
+ /* Remember where to put the results */
+ q->result = result;
+ q->domain = dname;
+ q->rid = rid;
+ q->sid_type = sid_type;
+ q->rc = rc;
+ q->n2s = n2s ? 1 : 0;
+ q->got_objectSid = 0;
+ q->got_objectClass = 0;
+ q->got_samAcctName = 0;
+
+ /*
+ * Provide sane defaults for the results in case we never hear
+ * back from the DS before closing the connection.
+ */
+ *rc = IDMAP_ERR_RETRIABLE_NET_ERR;
+ *sid_type = _IDMAP_T_OTHER;
+ *result = NULL;
+ if (dname != NULL)
+ *dname = NULL;
+ if (rid != NULL)
+ *rid = 0;
+
+ /* Send this lookup, don't wait for a result here */
+ (void) pthread_mutex_lock(&state->qadh->lock);
+
+ if (!state->qadh->dead) {
+ state->qadh->idletime = time(NULL);
+ lrc = ldap_search_ext(state->qadh->ld, basedn,
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL,
+ NULL, -1, &q->msgid);
+ if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE ||
+ lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN ||
+ lrc == LDAP_UNWILLING_TO_PERFORM) {
+ retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
+ state->qadh->dead = 1;
+ } else if (lrc != LDAP_SUCCESS) {
+ retcode = IDMAP_ERR_OTHER;
+ state->qadh->dead = 1;
+ }
+ }
+ (void) pthread_mutex_unlock(&state->qadh->lock);
+
+ if (state->qadh->dead)
+ return (retcode);
+
+ atomic_inc_32(&state->qinflight);
+
+ /*
+ * Reap as many requests as we can _without_ waiting
+ *
+ * We do this to prevent any possible TCP socket buffer
+ * starvation deadlocks.
+ */
+ (void) memset(&tv, 0, sizeof (tv));
+ while (idmap_get_adobject_batch(state->qadh, &tv) == 0)
+ ;
+
+ return (IDMAP_SUCCESS);
+}
+
+idmap_retcode
+idmap_name2sid_batch_add1(idmap_query_state_t *state,
+ const char *name, const char *dname,
+ char **sid, rid_t *rid, int *sid_type, idmap_retcode *rc)
+{
+ idmap_retcode retcode;
+ int flen, samAcctNameLen;
+ char *filter = NULL;
+ char *basedn = NULL;
+ char *cp;
+
+ /*
+ * Strategy: search [the global catalog] for user/group by
+ * sAMAccountName = user/groupname with base DN derived from the
+ * domain name. The objectSid and objectClass of the result are
+ * all we need to figure out the SID of the user/group and
+ * whether it is a user or a group.
+ */
+
+ /*
+ * Handle optional domain parameter and default domain
+ * semantics. The get a basedn from the domainname.
+ */
+ if (dname == NULL || *dname != '\0') {
+ /* domain name not given separately */
+ if ((cp = strchr(name, '@')) == NULL) {
+ /* nor is the name qualified */
+ dname = state->qadh->owner->dflt_w2k_dom;
+ basedn = state->qadh->owner->basedn;
+ samAcctNameLen = strlen(name);
+ } else {
+ /* the name is qualified */
+ /* LINTED */
+ samAcctNameLen = cp - name;
+ dname = cp + 1;
+ }
+ }
+
+ if (basedn == NULL)
+ basedn = dns2dn(dname);
+
+ /* Assemble filter */
+ flen = snprintf(NULL, 0, SANFILTER, samAcctNameLen, name) + 1;
+ if ((filter = (char *)malloc(flen)) == NULL) {
+ if (basedn != state->qadh->owner->basedn)
+ free(basedn);
+ return (IDMAP_ERR_MEMORY);
+ }
+ (void) snprintf(filter, flen, SANFILTER, samAcctNameLen, name);
+
+ retcode = idmap_batch_add1(state, 1, filter, basedn,
+ sid, NULL, rid, sid_type, rc);
+
+ if (basedn != state->qadh->owner->basedn)
+ free(basedn);
+ free(filter);
+
+ return (retcode);
+}
+
+idmap_retcode
+idmap_sid2name_batch_add1(idmap_query_state_t *state,
+ const char *sid, const rid_t *rid,
+ char **name, char **dname, int *sid_type, idmap_retcode *rc)
+{
+ idmap_retcode retcode;
+ int flen, ret;
+ char *filter = NULL;
+ char cbinsid[MAXHEXBINSID + 1];
+
+ /*
+ * Strategy: search [the global catalog] for user/group by
+ * objectSid = SID with empty base DN. The DN, sAMAccountName
+ * and objectClass of the result are all we need to figure out
+ * the name of the SID and whether it is a user, a group or a
+ * computer.
+ */
+
+ ret = idmap_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid));
+ if (ret != 0)
+ return (IDMAP_ERR_SID);
+
+ /* Assemble filter */
+ flen = snprintf(NULL, 0, OBJECTSIDFILTER, cbinsid) + 1;
+ if ((filter = (char *)malloc(flen)) == NULL)
+ return (IDMAP_ERR_MEMORY);
+ (void) snprintf(filter, flen, OBJECTSIDFILTER, cbinsid);
+
+ retcode = idmap_batch_add1(state, 0, filter, NULL, name, dname,
+ NULL, sid_type, rc);
+
+ free(filter);
+
+ return (retcode);
+}
diff --git a/usr/src/cmd/idmap/idmapd/adutils.h b/usr/src/cmd/idmap/idmapd/adutils.h
new file mode 100644
index 0000000000..bbee846352
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/adutils.h
@@ -0,0 +1,182 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ADUTILS_H
+#define _ADUTILS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Processes name2sid & sid2name lookups for a given user or computer
+ * from an AD Difrectory server using GSSAPI authentication
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <lber.h>
+#include <ldap.h>
+#include <sasl/sasl.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <time.h>
+#include <thread.h>
+#include <synch.h>
+#include "idmap_prot.h"
+#include <sys/idmap.h>
+
+/*
+ * idmapd interfaces stolen? from other idmapd code?
+ */
+
+/*
+ * Eventually these should be an enum here, but instead we share a
+ * namespace with other things in idmapd.
+ */
+#define _IDMAP_T_OTHER 0
+#define _IDMAP_T_USER -1004
+#define _IDMAP_T_GROUP -1005
+#define _IDMAP_T_DOMAIN -1006
+#define _IDMAP_T_COMPUTER -1007
+
+#define SID_MAX_SUB_AUTHORITIES 15
+#define MAXBINSID (1 + 1 + 6 + (SID_MAX_SUB_AUTHORITIES * 4))
+#define MAXHEXBINSID (MAXBINSID * 3)
+
+typedef uint32_t rid_t;
+
+/*
+ * We use the port numbers for normal LDAP and global catalog LDAP as
+ * the enum values for this enumeration. Clever? Silly? You decide.
+ * Although we never actually use these enum values as port numbers and
+ * never will, so this is just cute.
+ */
+typedef enum idmap_ad_partition {
+ IDMAP_AD_DATA = 389,
+ IDMAP_AD_GLOBAL_CATALOG = 3268
+} idmap_ad_partition_t;
+
+typedef struct ad ad_t;
+typedef struct idmap_query_state idmap_query_state_t;
+
+/*
+ * Idmap interfaces:
+ *
+ * - an ad_t represents an AD partition
+ * - a DS (hostname + port, if port != 0) can be added/removed from an ad_t
+ * - and because libldap supports space-separated lists of servers, a
+ * single hostname value can actually be a set of hostnames.
+ * - an ad_t can be allocated, ref'ed and released; last release
+ * releases resources
+ *
+ * - lookups are batched; see below.
+ *
+ * See below.
+ */
+
+/* Allocate/release ad_t objects */
+int idmap_ad_alloc(ad_t **new_ad, const char *default_domain,
+ idmap_ad_partition_t part);
+void idmap_ad_free(ad_t **ad);
+
+/* Add/remove a DS to/from an ad_t */
+int idmap_add_ds(ad_t *ad, const char *host, int port);
+void idmap_delete_ds(ad_t *ad, const char *host, int port);
+
+/*
+ * Batch lookups
+ *
+ * Start a batch, add queries to the batch one by one (the output
+ * pointers should all differ, so that a query's results don't clobber
+ * any other's), end the batch to wait for replies for all outstanding
+ * queries. The output parameters of each query are initialized to NULL
+ * or -1 as appropriate.
+ *
+ * LDAP searches are sent one by one without waiting (i.e., blocking)
+ * for replies. Replies are handled as soon as they are available.
+ * Missing replies are waited for only when idmap_lookup_batch_end() is
+ * called.
+ *
+ * If an add1 function returns != 0 then abort the batch by calling
+ * idmap_lookup_batch_end(), but note that some queries may have been
+ * answered, so check the result code of each query.
+ */
+
+/* Start a batch of lookups */
+idmap_retcode idmap_lookup_batch_start(ad_t *ad, int nqueries,
+ idmap_query_state_t **state);
+
+/* End a batch and release its idmap_query_state_t object */
+idmap_retcode idmap_lookup_batch_end(idmap_query_state_t **state,
+ struct timeval *timeout);
+
+/* Abandon a batch and release its idmap_query_state_t object */
+void idmap_lookup_free_batch(idmap_query_state_t **state);
+
+/*
+ * Add a name->SID lookup
+ *
+ * - 'dname' is optional; if NULL or empty string then 'name' has to be
+ * a user/group name qualified wih a domainname (e.g., foo@domain),
+ * else the 'name' must not be qualified and the domainname must be
+ * passed in 'dname'.
+ *
+ * - if 'rid' is NULL then the output SID string will include the last
+ * RID, else it won't and the last RID value will be stored in *rid.
+ *
+ * The caller must free() *sid.
+ */
+idmap_retcode idmap_name2sid_batch_add1(idmap_query_state_t *state,
+ const char *name, const char *dname,
+ char **sid, rid_t *rid, int *sid_type, idmap_retcode *rc);
+/*
+ * Add a SID->name lookup
+ *
+ * - 'rid' is optional; if NULL then 'sid' is expected to have the
+ * user/group RID present, else 'sid' is expected not to have it, and
+ * *rid will be used to qualify the given 'sid'
+ *
+ * - 'dname' is optional; if NULL then the fully qualified user/group
+ * name will be stored in *name, else the domain name will be stored in
+ * *dname and the user/group name will be stored in *name without a
+ * domain qualifier.
+ *
+ * The caller must free() *name and *dname (if present).
+ */
+idmap_retcode idmap_sid2name_batch_add1(idmap_query_state_t *state,
+ const char *sid, const rid_t *rid,
+ char **name, char **dname, int *sid_type, idmap_retcode *rc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ADUTILS_H */
diff --git a/usr/src/cmd/idmap/idmapd/dbutils.c b/usr/src/cmd/idmap/idmapd/dbutils.c
new file mode 100644
index 0000000000..05786f4e35
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/dbutils.c
@@ -0,0 +1,2665 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Database related utility routines
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <sys/sid.h>
+#include <time.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "idmapd.h"
+#include "adutils.h"
+#include "string.h"
+#include "idmap_priv.h"
+
+static idmap_retcode sql_compile_n_step_once(sqlite *, char *,
+ sqlite_vm **, int *, int, const char ***);
+
+#define EMPTY_NAME(name) (*name == 0 || strcmp(name, "\"\"") == 0)
+
+#define EMPTY_STRING(str) (str == NULL || *str == 0)
+
+#define DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
+ (req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
+
+#define AVOID_NAMESERVICE(req)\
+ (req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
+
+#define IS_EPHEMERAL(pid) (pid > INT32_MAX)
+
+#define LOCALRID_MIN 1000
+
+#define SLEEP_TIME 20
+
+#define NANO_SLEEP(rqtp, nsec)\
+ rqtp.tv_sec = 0;\
+ rqtp.tv_nsec = nsec * (NANOSEC / MILLISEC);\
+ (void) nanosleep(&rqtp, NULL);
+
+
+typedef enum init_db_option {
+ FAIL_IF_CORRUPT = 0,
+ REMOVE_IF_CORRUPT = 1
+} init_db_option_t;
+
+
+/*
+ * Initialize 'dbname' using 'sql'
+ */
+static int
+init_db_instance(const char *dbname, const char *sql, init_db_option_t opt,
+ int *new_db_created)
+{
+ int rc = 0;
+ int tries = 0;
+ sqlite *db = NULL;
+ char *str = NULL;
+
+ if (new_db_created != NULL)
+ *new_db_created = 0;
+
+ db = sqlite_open(dbname, 0600, &str);
+ while (db == NULL) {
+ idmapdlog(LOG_ERR,
+ "Error creating database %s (%s)",
+ dbname, CHECK_NULL(str));
+ sqlite_freemem(str);
+ if (opt == FAIL_IF_CORRUPT || opt != REMOVE_IF_CORRUPT ||
+ tries > 0)
+ return (-1);
+
+ tries++;
+ (void) unlink(dbname);
+ db = sqlite_open(dbname, 0600, &str);
+ }
+
+ sqlite_busy_timeout(db, 3000);
+ rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &str);
+ if (SQLITE_OK != rc) {
+ idmapdlog(LOG_ERR, "Cannot begin database transaction (%s)",
+ str);
+ sqlite_freemem(str);
+ sqlite_close(db);
+ return (1);
+ }
+
+ switch (sqlite_exec(db, sql, NULL, NULL, &str)) {
+ case SQLITE_ERROR:
+/*
+ * This is the normal situation: CREATE probably failed because tables
+ * already exist. It may indicate an error in SQL as well, but we cannot
+ * tell.
+ */
+ sqlite_freemem(str);
+ rc = sqlite_exec(db, "ROLLBACK TRANSACTION",
+ NULL, NULL, &str);
+ break;
+ case SQLITE_OK:
+ rc = sqlite_exec(db, "COMMIT TRANSACTION",
+ NULL, NULL, &str);
+ idmapdlog(LOG_INFO,
+ "Database created at %s", dbname);
+
+ if (new_db_created != NULL)
+ *new_db_created = 1;
+ break;
+ default:
+ idmapdlog(LOG_ERR,
+ "Error initializing database %s (%s)",
+ dbname, str);
+ sqlite_freemem(str);
+ rc = sqlite_exec(db, "ROLLBACK TRANSACTION",
+ NULL, NULL, &str);
+ break;
+ }
+
+ if (SQLITE_OK != rc) {
+ /* this is bad - database may be left in a locked state */
+ idmapdlog(LOG_ERR,
+ "Error closing transaction (%s)", str);
+ sqlite_freemem(str);
+ }
+
+ (void) sqlite_close(db);
+ return (rc);
+}
+
+/*
+ * Get the database handle
+ */
+idmap_retcode
+get_db_handle(sqlite **db) {
+ char *errmsg;
+
+ /*
+ * TBD RFE: Retrieve the db handle from thread-specific storage
+ * If none exists, open and store in thread-specific storage.
+ */
+
+ *db = sqlite_open(IDMAP_DBNAME, 0, &errmsg);
+ if (*db == NULL) {
+ idmapdlog(LOG_ERR,
+ "Error opening database %s (%s)",
+ IDMAP_DBNAME, CHECK_NULL(errmsg));
+ sqlite_freemem(errmsg);
+ return (IDMAP_ERR_INTERNAL);
+ }
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * Get the cache handle
+ */
+idmap_retcode
+get_cache_handle(sqlite **db) {
+ char *errmsg;
+
+ /*
+ * TBD RFE: Retrieve the db handle from thread-specific storage
+ * If none exists, open and store in thread-specific storage.
+ */
+
+ *db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg);
+ if (*db == NULL) {
+ idmapdlog(LOG_ERR,
+ "Error opening database %s (%s)",
+ IDMAP_CACHENAME, CHECK_NULL(errmsg));
+ sqlite_freemem(errmsg);
+ return (IDMAP_ERR_INTERNAL);
+ }
+ return (IDMAP_SUCCESS);
+}
+
+#define CACHE_SQL\
+ "CREATE TABLE idmap_cache ("\
+ " sidprefix TEXT,"\
+ " rid INTEGER,"\
+ " windomain TEXT,"\
+ " winname TEXT,"\
+ " pid INTEGER,"\
+ " unixname TEXT,"\
+ " is_user INTEGER,"\
+ " w2u INTEGER,"\
+ " u2w INTEGER,"\
+ " expiration INTEGER"\
+ ");"\
+ "CREATE UNIQUE INDEX idmap_cache_sid_w2u ON idmap_cache"\
+ " (sidprefix, rid, w2u);"\
+ "CREATE UNIQUE INDEX idmap_cache_pid_u2w ON idmap_cache"\
+ " (pid, is_user, u2w);"\
+ "CREATE TABLE name_cache ("\
+ " sidprefix TEXT,"\
+ " rid INTEGER,"\
+ " name TEXT,"\
+ " domain TEXT,"\
+ " type INTEGER,"\
+ " expiration INTEGER"\
+ ");"\
+ "CREATE UNIQUE INDEX name_cache_sid ON name_cache"\
+ " (sidprefix, rid);"
+
+#define DB_SQL\
+ "CREATE TABLE namerules ("\
+ " is_user INTEGER NOT NULL,"\
+ " windomain TEXT,"\
+ " winname TEXT NOT NULL,"\
+ " is_nt4 INTEGER NOT NULL,"\
+ " unixname NOT NULL,"\
+ " w2u_order INTEGER,"\
+ " u2w_order INTEGER"\
+ ");"\
+ "CREATE UNIQUE INDEX namerules_w2u ON namerules"\
+ " (winname, windomain, is_user, w2u_order);"\
+ "CREATE UNIQUE INDEX namerules_u2w ON namerules"\
+ " (unixname, is_user, u2w_order);"
+
+/*
+ * Initialize cache and db
+ */
+int
+init_dbs() {
+ /* name-based mappings; probably OK to blow away in a pinch(?) */
+ if (init_db_instance(IDMAP_DBNAME, DB_SQL, FAIL_IF_CORRUPT, NULL) < 0)
+ return (-1);
+
+ /* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */
+ if (init_db_instance(IDMAP_CACHENAME, CACHE_SQL, REMOVE_IF_CORRUPT,
+ &_idmapdstate.new_eph_db) < 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Finalize databases
+ */
+void
+fini_dbs() {
+}
+
+/*
+ * This table is a listing of status codes that will returned to the
+ * client when a SQL command fails with the corresponding error message.
+ */
+static msg_table_t sqlmsgtable[] = {
+ {IDMAP_ERR_U2W_NAMERULE,
+ "columns unixname, is_user, u2w_order are not unique"},
+ {IDMAP_ERR_W2U_NAMERULE,
+ "columns winname, windomain, is_user, w2u_order are not unique"},
+ {-1, NULL}
+};
+
+/*
+ * idmapd's version of string2stat to map SQLite messages to
+ * status codes
+ */
+idmap_retcode
+idmapd_string2stat(const char *msg) {
+ int i;
+ for (i = 0; sqlmsgtable[i].msg; i++) {
+ if (strcasecmp(sqlmsgtable[i].msg, msg) == 0)
+ return (sqlmsgtable[i].retcode);
+ }
+ return (IDMAP_ERR_OTHER);
+}
+
+/*
+ * Execute the given SQL statment without using any callbacks
+ */
+idmap_retcode
+sql_exec_no_cb(sqlite *db, char *sql) {
+ char *errmsg = NULL;
+ int r, i, s;
+ struct timespec rqtp;
+ idmap_retcode retcode;
+
+ for (i = 0, s = SLEEP_TIME; i < MAX_TRIES; i++, s *= 2) {
+ if (errmsg) {
+ sqlite_freemem(errmsg);
+ errmsg = NULL;
+ }
+ r = sqlite_exec(db, sql, NULL, NULL, &errmsg);
+ if (r != SQLITE_BUSY)
+ break;
+ NANO_SLEEP(rqtp, s);
+ }
+
+ if (r != SQLITE_OK) {
+ idmapdlog(LOG_ERR, "Database error during %s (%s)",
+ sql, CHECK_NULL(errmsg));
+ if (r == SQLITE_BUSY) {
+ retcode = IDMAP_ERR_BUSY;
+ } else {
+ retcode = idmap_string2stat(errmsg);
+ if (retcode == IDMAP_ERR_OTHER)
+ retcode = idmapd_string2stat(errmsg);
+ }
+ if (errmsg)
+ sqlite_freemem(errmsg);
+ return (retcode);
+ }
+
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * Generate expression that can be used in WHERE statements.
+ * Examples:
+ * <prefix> <col> <op> <value> <suffix>
+ * "" "unixuser" "=" "foo" "AND"
+ */
+idmap_retcode
+gen_sql_expr_from_utf8str(const char *prefix, const char *col,
+ const char *op, idmap_utf8str *value,
+ const char *suffix, char **out) {
+ char *str;
+ idmap_stat retcode;
+
+ if (out == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (value == NULL)
+ return (IDMAP_SUCCESS);
+
+ retcode = idmap_utf82str(&str, 0, value);
+ if (retcode != IDMAP_SUCCESS)
+ return (retcode);
+
+ if (prefix == NULL)
+ prefix = "";
+ if (suffix == NULL)
+ suffix = "";
+
+ *out = sqlite_mprintf("%s %s %s %Q %s",
+ prefix, col, op, str, suffix);
+ idmap_free(str);
+ if (*out == NULL)
+ return (IDMAP_ERR_MEMORY);
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * Generate and execute SQL statement for LIST RPC calls
+ */
+idmap_retcode
+process_list_svc_sql(sqlite *db, char *sql, uint64_t limit,
+ list_svc_cb cb, void *result) {
+ list_cb_data_t cb_data;
+ char *errmsg = NULL;
+ int r, i, s;
+ struct timespec rqtp;
+ idmap_retcode retcode = IDMAP_ERR_INTERNAL;
+
+ (void) memset(&cb_data, 0, sizeof (cb_data));
+ cb_data.result = result;
+ cb_data.limit = limit;
+
+ for (i = 0, s = SLEEP_TIME; i < MAX_TRIES; i++, s *= 2) {
+ r = sqlite_exec(db, sql, cb, &cb_data, &errmsg);
+ switch (r) {
+ case SQLITE_OK:
+ retcode = IDMAP_SUCCESS;
+ goto out;
+ case SQLITE_BUSY:
+ if (errmsg) {
+ sqlite_freemem(errmsg);
+ errmsg = NULL;
+ }
+ retcode = IDMAP_ERR_BUSY;
+ idmapdlog(LOG_DEBUG,
+ "Database busy, %d retries remaining",
+ MAX_TRIES - i - 1);
+ NANO_SLEEP(rqtp, s);
+ continue;
+ default:
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR,
+ "Database error during %s (%s)",
+ sql, CHECK_NULL(errmsg));
+ goto out;
+ };
+ }
+out:
+ if (errmsg)
+ sqlite_freemem(errmsg);
+ return (retcode);
+}
+
+/*
+ * This routine is called by callbacks that process the results of
+ * LIST RPC calls to validate data and to allocate memory for
+ * the result array.
+ */
+idmap_retcode
+validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv,
+ int ncol, uchar_t **list, size_t valsize) {
+ size_t nsize;
+ void *tmplist;
+
+ if (cb_data->limit > 0 && cb_data->next == cb_data->limit)
+ return (IDMAP_NEXT);
+
+ if (argc < ncol || argv == NULL) {
+ idmapdlog(LOG_ERR, "Invalid data");
+ return (IDMAP_ERR_INTERNAL);
+ }
+
+ /* alloc in bulk to reduce number of reallocs */
+ if (cb_data->next >= cb_data->len) {
+ nsize = (cb_data->len + SIZE_INCR) * valsize;
+ tmplist = realloc(*list, nsize);
+ if (tmplist == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ return (IDMAP_ERR_MEMORY);
+ }
+ *list = tmplist;
+ (void) memset(*list + (cb_data->len * valsize), 0,
+ SIZE_INCR * valsize);
+ cb_data->len += SIZE_INCR;
+ }
+ return (IDMAP_SUCCESS);
+}
+
+static idmap_retcode
+get_namerule_order(char *winname, char *windomain, char *unixname,
+ int direction, int *w2u_order, int *u2w_order) {
+
+ *w2u_order = 0;
+ *u2w_order = 0;
+
+ /*
+ * Windows to UNIX lookup order:
+ * 1. winname@domain (or winname) to ""
+ * 2. winname@domain (or winname) to unixname
+ * 3. winname@* to ""
+ * 4. winname@* to unixname
+ * 5. *@domain (or *) to *
+ * 6. *@domain (or *) to ""
+ * 7. *@domain (or *) to unixname
+ * 8. *@* to *
+ * 9. *@* to ""
+ * 10. *@* to unixname
+ *
+ * winname is a special case of winname@domain when domain is the
+ * default domain. Similarly * is a special case of *@domain when
+ * domain is the default domain.
+ *
+ * Note that "" has priority over specific names because "" inhibits
+ * mappings and traditionally deny rules always had higher priority.
+ */
+ if (direction == 0 || direction == 1) {
+ if (winname == NULL)
+ return (IDMAP_ERR_W2U_NAMERULE);
+ else if (unixname == NULL)
+ return (IDMAP_ERR_W2U_NAMERULE);
+ else if (EMPTY_NAME(winname))
+ return (IDMAP_ERR_W2U_NAMERULE);
+ else if (*winname == '*' && windomain && *windomain == '*') {
+ if (*unixname == '*')
+ *w2u_order = 8;
+ else if (EMPTY_NAME(unixname))
+ *w2u_order = 9;
+ else /* unixname == name */
+ *w2u_order = 10;
+ } else if (*winname == '*') {
+ if (*unixname == '*')
+ *w2u_order = 5;
+ else if (EMPTY_NAME(unixname))
+ *w2u_order = 6;
+ else /* name */
+ *w2u_order = 7;
+ } else if (windomain && *windomain == '*') {
+ /* winname == name */
+ if (*unixname == '*')
+ return (IDMAP_ERR_W2U_NAMERULE);
+ else if (EMPTY_NAME(unixname))
+ *w2u_order = 3;
+ else /* name */
+ *w2u_order = 4;
+ } else {
+ /* winname == name && windomain == null or name */
+ if (*unixname == '*')
+ return (IDMAP_ERR_W2U_NAMERULE);
+ else if (EMPTY_NAME(unixname))
+ *w2u_order = 1;
+ else /* name */
+ *w2u_order = 2;
+ }
+ }
+
+ /*
+ * 1. unixname to ""
+ * 2. unixname to winname@domain (or winname)
+ * 3. * to *@domain (or *)
+ * 4. * to ""
+ * 5. * to winname@domain (or winname)
+ */
+ if (direction == 0 || direction == 2) {
+ if (unixname == NULL || EMPTY_NAME(unixname))
+ return (IDMAP_ERR_U2W_NAMERULE);
+ else if (winname == NULL)
+ return (IDMAP_ERR_U2W_NAMERULE);
+ else if (*unixname == '*') {
+ if (*winname == '*')
+ *u2w_order = 3;
+ else if (EMPTY_NAME(winname))
+ *u2w_order = 4;
+ else
+ *u2w_order = 5;
+ } else {
+ if (*winname == '*')
+ return (IDMAP_ERR_U2W_NAMERULE);
+ else if (EMPTY_NAME(winname))
+ *u2w_order = 1;
+ else
+ *u2w_order = 2;
+ }
+ }
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * Generate and execute SQL statement to add name-based mapping rule
+ */
+idmap_retcode
+add_namerule(sqlite *db, idmap_namerule *rule) {
+ char *sql = NULL;
+ idmap_stat retcode;
+ char *windomain = NULL, *winname = NULL, *dom;
+ char *unixname = NULL;
+ int w2u_order, u2w_order;
+ char w2ubuf[11], u2wbuf[11];
+
+ retcode = idmap_utf82str(&windomain, 0, &rule->windomain);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+ retcode = idmap_utf82str(&winname, 0, &rule->winname);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+ retcode = idmap_utf82str(&unixname, 0, &rule->unixname);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+
+ retcode = get_namerule_order(winname, windomain, unixname,
+ rule->direction, &w2u_order, &u2w_order);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+
+ if (w2u_order)
+ (void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order);
+ if (u2w_order)
+ (void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order);
+
+ /* Use NULL instead of 0 for w2u_order and u2w_order */
+
+ RDLOCK_CONFIG();
+ if (windomain)
+ dom = windomain;
+ else if (_idmapdstate.cfg->pgcfg.mapping_domain)
+ dom = _idmapdstate.cfg->pgcfg.mapping_domain;
+ else
+ dom = "";
+ sql = sqlite_mprintf("INSERT OR ROLLBACK into namerules "
+ "(is_user, windomain, winname, is_nt4, "
+ "unixname, w2u_order, u2w_order) "
+ "VALUES(%d, %Q, %Q, %d, %Q, %q, %q);",
+ rule->is_user?1:0,
+ dom,
+ winname, rule->is_nt4?1:0,
+ unixname,
+ w2u_order?w2ubuf:NULL,
+ u2w_order?u2wbuf:NULL);
+ UNLOCK_CONFIG();
+
+ if (sql == NULL) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ retcode = sql_exec_no_cb(db, sql);
+
+ if (retcode == IDMAP_ERR_OTHER)
+ retcode = IDMAP_ERR_CFG;
+
+out:
+ if (windomain)
+ idmap_free(windomain);
+ if (winname)
+ idmap_free(winname);
+ if (unixname)
+ idmap_free(unixname);
+ if (sql)
+ sqlite_freemem(sql);
+ return (retcode);
+}
+
+/*
+ * Flush name-based mapping rules
+ */
+idmap_retcode
+flush_namerules(sqlite *db, bool_t is_user) {
+ char *sql = NULL;
+ idmap_stat retcode;
+
+ sql = sqlite_mprintf("DELETE FROM namerules WHERE "
+ "is_user = %d;", is_user?1:0);
+
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ return (IDMAP_ERR_MEMORY);
+ }
+
+ retcode = sql_exec_no_cb(db, sql);
+
+ sqlite_freemem(sql);
+ return (retcode);
+}
+
+/*
+ * Generate and execute SQL statement to remove a name-based mapping rule
+ */
+idmap_retcode
+rm_namerule(sqlite *db, idmap_namerule *rule) {
+ char *sql = NULL;
+ idmap_stat retcode;
+ char *s_windomain = NULL, *s_winname = NULL;
+ char *s_unixname = NULL;
+ char buf[80];
+
+ if (rule->direction < 0 &&
+ rule->windomain.idmap_utf8str_len < 1 &&
+ rule->winname.idmap_utf8str_len < 1 &&
+ rule->unixname.idmap_utf8str_len < 1)
+ return (IDMAP_SUCCESS);
+
+ if (rule->direction < 0) {
+ buf[0] = 0;
+ } else if (rule->direction == 0) {
+ (void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
+ " AND u2w_order > 0");
+ } else if (rule->direction == 1) {
+ (void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
+ " AND (u2w_order = 0 OR u2w_order ISNULL)");
+ } else if (rule->direction == 2) {
+ (void) snprintf(buf, sizeof (buf), "AND u2w_order > 0"
+ " AND (w2u_order = 0 OR w2u_order ISNULL)");
+ }
+
+ retcode = IDMAP_ERR_INTERNAL;
+ if (rule->windomain.idmap_utf8str_len > 0) {
+ if (gen_sql_expr_from_utf8str("AND", "windomain", "=",
+ &rule->windomain,
+ "", &s_windomain) != IDMAP_SUCCESS)
+ goto out;
+ }
+
+ if (rule->winname.idmap_utf8str_len > 0) {
+ if (gen_sql_expr_from_utf8str("AND", "winname", "=",
+ &rule->winname,
+ "", &s_winname) != IDMAP_SUCCESS)
+ goto out;
+ }
+
+ if (rule->unixname.idmap_utf8str_len > 0) {
+ if (gen_sql_expr_from_utf8str("AND", "unixname", "=",
+ &rule->unixname,
+ "", &s_unixname) != IDMAP_SUCCESS)
+ goto out;
+ }
+
+ sql = sqlite_mprintf("DELETE FROM namerules WHERE "
+ "is_user = %d %s %s %s %s;",
+ rule->is_user?1:0,
+ s_windomain?s_windomain:"",
+ s_winname?s_winname:"",
+ s_unixname?s_unixname:"",
+ buf);
+
+ if (sql == NULL) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ retcode = sql_exec_no_cb(db, sql);
+
+out:
+ if (s_windomain)
+ sqlite_freemem(s_windomain);
+ if (s_winname)
+ sqlite_freemem(s_winname);
+ if (s_unixname)
+ sqlite_freemem(s_unixname);
+ if (sql)
+ sqlite_freemem(sql);
+ return (retcode);
+}
+
+/*
+ * Compile the given SQL query and step just once.
+ *
+ * Input:
+ * db - db handle
+ * sql - SQL statement
+ *
+ * Output:
+ * vm - virtual SQL machine
+ * ncol - number of columns in the result
+ * values - column values
+ *
+ * Return values:
+ * IDMAP_SUCCESS
+ * IDMAP_ERR_BUSY
+ * IDMAP_ERR_NOTFOUND
+ * IDMAP_ERR_INTERNAL
+ */
+
+static idmap_retcode
+sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
+ int reqcol, const char ***values) {
+ char *errmsg = NULL;
+ struct timespec rqtp;
+ int i, r, s;
+
+ if (sqlite_compile(db, sql, NULL, vm, &errmsg) != SQLITE_OK) {
+ idmapdlog(LOG_ERR,
+ "Database error during %s (%s)",
+ sql, CHECK_NULL(errmsg));
+ sqlite_freemem(errmsg);
+ return (IDMAP_ERR_INTERNAL);
+ }
+
+ for (i = 0, s = SLEEP_TIME; i < MAX_TRIES; i++, s *= 2) {
+ r = sqlite_step(*vm, ncol, values, NULL);
+ if (r != SQLITE_BUSY)
+ break;
+ NANO_SLEEP(rqtp, s);
+ }
+
+ if (r == SQLITE_BUSY) {
+ (void) sqlite_finalize(*vm, NULL);
+ *vm = NULL;
+ return (IDMAP_ERR_BUSY);
+ } else if (r == SQLITE_ROW) {
+ if (ncol && *ncol < reqcol) {
+ (void) sqlite_finalize(*vm, NULL);
+ *vm = NULL;
+ return (IDMAP_ERR_INTERNAL);
+ }
+ /* Caller will call finalize after using the results */
+ return (IDMAP_SUCCESS);
+ } else if (r == SQLITE_DONE) {
+ (void) sqlite_finalize(*vm, NULL);
+ *vm = NULL;
+ return (IDMAP_ERR_NOTFOUND);
+ }
+
+ (void) sqlite_finalize(*vm, &errmsg);
+ *vm = NULL;
+ idmapdlog(LOG_ERR, "Database error during %s (%s)",
+ sql, CHECK_NULL(errmsg));
+ sqlite_freemem(errmsg);
+ return (IDMAP_ERR_INTERNAL);
+}
+
+static wksids_table_t wksidstable[] = {
+ {"S-1-5", 18, 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0},
+ {"S-1-5", 7, 0, GID_NOBODY, 0},
+ {"S-1-3", 0, 1, IDMAP_WK_CREATOR_OWNER_UID, 0},
+ {"S-1-3", 1, 0, IDMAP_WK_CREATOR_GROUP_GID, 0},
+ {NULL, UINT32_MAX, -1, UINT32_MAX, -1}
+};
+
+static idmap_retcode
+lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res) {
+ int i;
+ for (i = 0; wksidstable[i].sidprefix; i++) {
+ if ((strcasecmp(wksidstable[i].sidprefix,
+ req->id1.idmap_id_u.sid.prefix) == 0) &&
+ req->id1.idmap_id_u.sid.rid ==
+ wksidstable[i].rid &&
+ wksidstable[i].direction != 2) {
+ switch (req->id2.idtype) {
+ case IDMAP_UID:
+ if (wksidstable[i].is_user == 0)
+ return (IDMAP_ERR_NOTUSER);
+ res->id.idmap_id_u.uid = wksidstable[i].pid;
+ res->direction = wksidstable[i].direction;
+ return (IDMAP_SUCCESS);
+ case IDMAP_GID:
+ if (wksidstable[i].is_user == 1)
+ return (IDMAP_ERR_NOTGROUP);
+ res->id.idmap_id_u.gid = wksidstable[i].pid;
+ res->direction = wksidstable[i].direction;
+ return (IDMAP_SUCCESS);
+ case IDMAP_POSIXID:
+ res->id.idmap_id_u.uid = wksidstable[i].pid;
+ res->id.idtype = (!wksidstable[i].is_user)?
+ IDMAP_GID:IDMAP_UID;
+ res->direction = wksidstable[i].direction;
+ return (IDMAP_SUCCESS);
+ default:
+ return (IDMAP_ERR_NOTSUPPORTED);
+ }
+ }
+ }
+ return (IDMAP_ERR_NOTFOUND);
+}
+
+static idmap_retcode
+lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) {
+ int i;
+ for (i = 0; wksidstable[i].sidprefix; i++) {
+ if (req->id1.idmap_id_u.uid == wksidstable[i].pid &&
+ wksidstable[i].direction != 1 &&
+ (wksidstable[i].is_user < 0 ||
+ is_user == wksidstable[i].is_user)) {
+ switch (req->id2.idtype) {
+ case IDMAP_SID:
+ res->id.idmap_id_u.sid.rid =
+ wksidstable[i].rid;
+ res->id.idmap_id_u.sid.prefix =
+ strdup(wksidstable[i].sidprefix);
+ if (res->id.idmap_id_u.sid.prefix == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ return (IDMAP_ERR_MEMORY);
+ }
+ res->direction = wksidstable[i].direction;
+ return (IDMAP_SUCCESS);
+ default:
+ return (IDMAP_ERR_NOTSUPPORTED);
+ }
+ }
+ }
+ return (IDMAP_ERR_NOTFOUND);
+}
+
+static idmap_retcode
+lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
+ char *end;
+ char *sql = NULL;
+ const char **values;
+ sqlite_vm *vm = NULL;
+ int ncol, is_user;
+ uid_t pid;
+ idmap_utf8str *str;
+ time_t curtime, exp;
+ idmap_retcode retcode;
+
+ /* Current time */
+ errno = 0;
+ if ((curtime = time(NULL)) == (time_t)-1) {
+ idmapdlog(LOG_ERR,
+ "Failed to get current time (%s)",
+ strerror(errno));
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+
+ /* SQL to lookup the cache */
+ sql = sqlite_mprintf("SELECT pid, is_user, expiration, unixname, u2w "
+ "FROM idmap_cache WHERE "
+ "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
+ "(pid >= 2147483648 OR "
+ "(expiration = 0 OR expiration ISNULL OR "
+ "expiration > %d));",
+ req->id1.idmap_id_u.sid.prefix,
+ req->id1.idmap_id_u.sid.rid,
+ curtime);
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
+ sqlite_freemem(sql);
+
+ if (retcode == IDMAP_ERR_NOTFOUND) {
+ goto out;
+ } else if (retcode == IDMAP_SUCCESS) {
+ /* sanity checks */
+ if (values[0] == NULL || values[1] == NULL) {
+ retcode = IDMAP_ERR_CACHE;
+ goto out;
+ }
+
+ pid = strtoul(values[0], &end, 10);
+ is_user = strncmp(values[1], "0", 2)?1:0;
+
+ /*
+ * We may have an expired ephemeral mapping. Consider
+ * the expired entry as valid if we are not going to
+ * perform name-based mapping. But do not renew the
+ * expiration.
+ * If we will be doing name-based mapping then store the
+ * ephemeral pid in the result so that we can use it
+ * if we end up doing dynamic mapping again.
+ */
+ if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) &&
+ !AVOID_NAMESERVICE(req)) {
+ if (IS_EPHEMERAL(pid) && values[2]) {
+ exp = strtoll(values[2], &end, 10);
+ if (exp && exp <= curtime) {
+ /* Store the ephemeral pid */
+ res->id.idmap_id_u.uid = pid;
+ res->id.idtype = is_user?
+ IDMAP_UID:IDMAP_GID;
+ res->direction = 0;
+ req->direction |= is_user?
+ _IDMAP_F_EXP_EPH_UID:
+ _IDMAP_F_EXP_EPH_GID;
+ retcode = IDMAP_ERR_NOTFOUND;
+ goto out;
+ }
+ }
+ }
+
+ switch (req->id2.idtype) {
+ case IDMAP_UID:
+ if (!is_user)
+ retcode = IDMAP_ERR_NOTUSER;
+ else
+ res->id.idmap_id_u.uid = pid;
+ break;
+ case IDMAP_GID:
+ if (is_user)
+ retcode = IDMAP_ERR_NOTGROUP;
+ else
+ res->id.idmap_id_u.gid = pid;
+ break;
+ case IDMAP_POSIXID:
+ res->id.idmap_id_u.uid = pid;
+ res->id.idtype = (is_user)?IDMAP_UID:IDMAP_GID;
+ break;
+ default:
+ retcode = IDMAP_ERR_NOTSUPPORTED;
+ break;
+ }
+ }
+
+out:
+ if (retcode == IDMAP_SUCCESS) {
+ if (values[4])
+ res->direction =
+ (strtol(values[4], &end, 10) == 0)?1:0;
+ else
+ res->direction = 1;
+
+ if (values[3]) {
+ str = &req->id2name;
+ retcode = idmap_str2utf8(&str, values[3], 0);
+ if (retcode != IDMAP_SUCCESS) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ }
+ }
+ }
+ if (vm)
+ (void) sqlite_finalize(vm, NULL);
+ return (retcode);
+}
+
+static idmap_retcode
+_lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid,
+ char **name, char **domain, int *type) {
+ char *end;
+ char *sql = NULL;
+ const char **values;
+ sqlite_vm *vm = NULL;
+ int ncol;
+ time_t curtime;
+ idmap_retcode retcode = IDMAP_SUCCESS;
+
+ /* Get current time */
+ errno = 0;
+ if ((curtime = time(NULL)) == (time_t)-1) {
+ idmapdlog(LOG_ERR,
+ "Failed to get current time (%s)",
+ strerror(errno));
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+
+ /* SQL to lookup the cache */
+ sql = sqlite_mprintf("SELECT name, domain, type FROM name_cache WHERE "
+ "sidprefix = %Q AND rid = %u AND "
+ "(expiration = 0 OR expiration ISNULL OR "
+ "expiration > %d);",
+ sidprefix, rid, curtime);
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
+ sqlite_freemem(sql);
+
+ if (retcode == IDMAP_SUCCESS) {
+ if (type) {
+ if (values[2] == NULL) {
+ retcode = IDMAP_ERR_CACHE;
+ goto out;
+ }
+ *type = strtol(values[2], &end, 10);
+ }
+
+ if (name && values[0]) {
+ if ((*name = strdup(values[0])) == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ }
+
+ if (domain && values[1]) {
+ if ((*domain = strdup(values[1])) == NULL) {
+ if (name && *name) {
+ free(*name);
+ *name = NULL;
+ }
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ }
+ }
+
+out:
+ if (vm)
+ (void) sqlite_finalize(vm, NULL);
+ return (retcode);
+}
+
+static idmap_retcode
+verify_type(idmap_id_type idtype, int type, idmap_id_res *res) {
+ switch (idtype) {
+ case IDMAP_UID:
+ if (type != _IDMAP_T_USER)
+ return (IDMAP_ERR_NOTUSER);
+ res->id.idtype = IDMAP_UID;
+ break;
+ case IDMAP_GID:
+ if (type != _IDMAP_T_GROUP)
+ return (IDMAP_ERR_NOTGROUP);
+ res->id.idtype = IDMAP_GID;
+ break;
+ case IDMAP_POSIXID:
+ if (type == _IDMAP_T_USER)
+ res->id.idtype = IDMAP_UID;
+ else if (type == _IDMAP_T_GROUP)
+ res->id.idtype = IDMAP_GID;
+ else
+ return (IDMAP_ERR_SID);
+ break;
+ default:
+ return (IDMAP_ERR_NOTSUPPORTED);
+ }
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * Lookup cache for sid to name
+ */
+static idmap_retcode
+lookup_cache_sid2name(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
+ int type = -1;
+ idmap_retcode retcode;
+ char *sidprefix;
+ idmap_rid_t rid;
+ char *name = NULL, *domain = NULL;
+ idmap_utf8str *str;
+
+ sidprefix = req->id1.idmap_id_u.sid.prefix;
+ rid = req->id1.idmap_id_u.sid.rid;
+
+ /* Lookup sid to name in cache */
+ retcode = _lookup_cache_sid2name(cache, sidprefix, rid, &name,
+ &domain, &type);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+
+ /* Verify that the sid type matches the request */
+ retcode = verify_type(req->id2.idtype, type, res);
+
+out:
+ if (retcode == IDMAP_SUCCESS) {
+ /* update state in 'req' */
+ if (name) {
+ str = &req->id1name;
+ (void) idmap_str2utf8(&str, name, 1);
+ }
+ if (domain) {
+ str = &req->id1domain;
+ (void) idmap_str2utf8(&str, domain, 1);
+ }
+ } else {
+ if (name)
+ free(name);
+ if (domain)
+ free(domain);
+ }
+ return (retcode);
+}
+
+idmap_retcode
+lookup_win_batch_sid2name(lookup_state_t *state, idmap_mapping_batch *batch,
+ idmap_ids_res *result) {
+ idmap_retcode retcode;
+ int ret, i;
+ int retries = 0;
+ idmap_mapping *req;
+ idmap_id_res *res;
+
+ if (state->ad_nqueries == 0)
+ return (IDMAP_SUCCESS);
+
+retry:
+ ret = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries,
+ &state->ad_lookup);
+ if (ret != 0) {
+ idmapdlog(LOG_ERR,
+ "Failed to create sid2name batch for AD lookup");
+ return (IDMAP_ERR_INTERNAL);
+ }
+
+ for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
+ req = &batch->idmap_mapping_batch_val[i];
+ res = &result->ids.ids_val[i];
+
+ if (retries == 0)
+ res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
+ else if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
+ continue;
+
+ if (req->id1.idtype == IDMAP_SID &&
+ req->direction & _IDMAP_F_S2N_AD) {
+ retcode = idmap_sid2name_batch_add1(
+ state->ad_lookup,
+ req->id1.idmap_id_u.sid.prefix,
+ &req->id1.idmap_id_u.sid.rid,
+ &req->id1name.idmap_utf8str_val,
+ &req->id1domain.idmap_utf8str_val,
+ (int *)&res->id.idtype,
+ &res->retcode);
+
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
+ break;
+
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+ }
+ }
+
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
+ idmap_lookup_free_batch(&state->ad_lookup);
+ else
+ retcode = idmap_lookup_batch_end(&state->ad_lookup, NULL);
+
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
+ goto retry;
+
+ return (retcode);
+
+out:
+ idmapdlog(LOG_NOTICE, "Windows SID to user/group name lookup failed");
+ idmap_lookup_free_batch(&state->ad_lookup);
+ return (retcode);
+}
+
+idmap_retcode
+sid2pid_first_pass(lookup_state_t *state, sqlite *cache, idmap_mapping *req,
+ idmap_id_res *res) {
+ idmap_retcode retcode;
+
+ /*
+ * The req->direction field is used to maintain state of the
+ * sid2pid request.
+ */
+ req->direction = _IDMAP_F_DONE;
+
+ if (req->id1.idmap_id_u.sid.prefix == NULL) {
+ retcode = IDMAP_ERR_SID;
+ goto out;
+ }
+ res->id.idtype = req->id2.idtype;
+ res->id.idmap_id_u.uid = UID_NOBODY;
+
+ /* Lookup well-known SIDs */
+ retcode = lookup_wksids_sid2pid(req, res);
+ if (retcode != IDMAP_ERR_NOTFOUND)
+ goto out;
+
+ /* Lookup sid to pid in cache */
+ retcode = lookup_cache_sid2pid(cache, req, res);
+ if (retcode != IDMAP_ERR_NOTFOUND)
+ goto out;
+
+ if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
+ res->id.idmap_id_u.uid = SENTINEL_PID;
+ goto out;
+ }
+
+ /*
+ * Failed to find non-expired entry in cache. Tell the caller
+ * that we are not done yet.
+ */
+ state->sid2pid_done = FALSE;
+
+ /*
+ * Our next step is name-based mapping. To lookup name-based
+ * mapping rules, we need the windows name and domain-name
+ * associated with the SID.
+ */
+
+ /*
+ * Check if we already have the name (i.e name2pid lookups)
+ */
+ if (req->id1name.idmap_utf8str_val &&
+ req->id1domain.idmap_utf8str_val) {
+ retcode = IDMAP_SUCCESS;
+ req->direction |= _IDMAP_F_S2N_CACHE;
+ goto out;
+ }
+
+ /*
+ * Lookup sid to winname@domainname in cache.
+ * Note that since libldap caches LDAP results, we may remove
+ * the idmapd's cache eventually
+ */
+ retcode = lookup_cache_sid2name(cache, req, res);
+ if (retcode == IDMAP_ERR_NOTFOUND) {
+ /* Batch sid to name AD lookup request */
+ retcode = IDMAP_SUCCESS;
+ req->direction |= _IDMAP_F_S2N_AD;
+ state->ad_nqueries++;
+ goto out;
+ } else if (retcode != IDMAP_SUCCESS) {
+ goto out;
+ }
+
+ retcode = IDMAP_SUCCESS;
+ req->direction |= _IDMAP_F_S2N_CACHE;
+
+out:
+ res->retcode = idmap_stat4prot(retcode);
+ return (retcode);
+}
+
+/*
+ * Generate SID using the following convention
+ * <machine-sid-prefix>-<1000 + uid>
+ * <machine-sid-prefix>-<2^31 + gid>
+ */
+static idmap_retcode
+generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user) {
+
+ if (_idmapdstate.cfg->pgcfg.machine_sid) {
+ /* Skip 1000 UIDs */
+ if (is_user && req->id1.idmap_id_u.uid >
+ (INT32_MAX - LOCALRID_MIN))
+ return (IDMAP_ERR_NOTFOUND);
+
+ RDLOCK_CONFIG();
+ res->id.idmap_id_u.sid.prefix =
+ strdup(_idmapdstate.cfg->pgcfg.machine_sid);
+ if (res->id.idmap_id_u.sid.prefix == NULL) {
+ UNLOCK_CONFIG();
+ idmapdlog(LOG_ERR, "Out of memory");
+ return (IDMAP_ERR_MEMORY);
+ }
+ UNLOCK_CONFIG();
+ res->id.idmap_id_u.sid.rid =
+ (is_user)?req->id1.idmap_id_u.uid + LOCALRID_MIN:
+ req->id1.idmap_id_u.gid + INT32_MAX + 1;
+ res->direction = 0;
+
+ /*
+ * Don't update name_cache because local sids don't have
+ * valid windows names.
+ * We mark the entry as being found in the namecache so that
+ * the cache update routine doesn't update namecache.
+ */
+ req->direction = _IDMAP_F_S2N_CACHE;
+ }
+
+ return (IDMAP_SUCCESS);
+}
+
+static idmap_retcode
+lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) {
+ char *sidprefix;
+ uint32_t rid;
+ int s;
+
+ /*
+ * If the sidprefix == localsid then UID = last RID - 1000 or
+ * GID = last RID - 2^31.
+ */
+ sidprefix = req->id1.idmap_id_u.sid.prefix;
+ rid = req->id1.idmap_id_u.sid.rid;
+
+ RDLOCK_CONFIG();
+ s = (_idmapdstate.cfg->pgcfg.machine_sid)?
+ strcasecmp(sidprefix,
+ _idmapdstate.cfg->pgcfg.machine_sid):1;
+ UNLOCK_CONFIG();
+
+ if (s == 0) {
+ switch (req->id2.idtype) {
+ case IDMAP_UID:
+ if (rid > INT32_MAX) {
+ return (IDMAP_ERR_NOTUSER);
+ } else if (rid < LOCALRID_MIN) {
+ return (IDMAP_ERR_NOTFOUND);
+ }
+ res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
+ res->id.idtype = IDMAP_UID;
+ break;
+ case IDMAP_GID:
+ if (rid <= INT32_MAX) {
+ return (IDMAP_ERR_NOTGROUP);
+ }
+ res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
+ res->id.idtype = IDMAP_GID;
+ break;
+ case IDMAP_POSIXID:
+ if (rid > INT32_MAX) {
+ res->id.idmap_id_u.gid =
+ rid - INT32_MAX - 1;
+ res->id.idtype = IDMAP_GID;
+ } else if (rid < LOCALRID_MIN) {
+ return (IDMAP_ERR_NOTFOUND);
+ } else {
+ res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
+ res->id.idtype = IDMAP_UID;
+ }
+ break;
+ default:
+ return (IDMAP_ERR_NOTSUPPORTED);
+ }
+ return (IDMAP_SUCCESS);
+ }
+
+ return (IDMAP_ERR_NOTFOUND);
+}
+
+static idmap_retcode
+ns_lookup_byname(int is_user, const char *name, idmap_id_res *res) {
+ struct passwd pwd;
+ struct group grp;
+ char buf[1024];
+ int errnum;
+ const char *me = "ns_lookup_byname";
+
+ if (is_user) {
+ if (getpwnam_r(name, &pwd, buf, sizeof (buf)) == NULL) {
+ errnum = errno;
+ idmapdlog(LOG_WARNING,
+ "%s: getpwnam_r(%s) failed (%s).",
+ me, name,
+ errnum?strerror(errnum):"not found");
+ if (errnum == 0)
+ return (IDMAP_ERR_NOTFOUND);
+ else
+ return (IDMAP_ERR_INTERNAL);
+ }
+ res->id.idmap_id_u.uid = pwd.pw_uid;
+ res->id.idtype = IDMAP_UID;
+ } else {
+ if (getgrnam_r(name, &grp, buf, sizeof (buf)) == NULL) {
+ errnum = errno;
+ idmapdlog(LOG_WARNING,
+ "%s: getgrnam_r(%s) failed (%s).",
+ me, name,
+ errnum?strerror(errnum):"not found");
+ if (errnum == 0)
+ return (IDMAP_ERR_NOTFOUND);
+ else
+ return (IDMAP_ERR_INTERNAL);
+ }
+ res->id.idmap_id_u.gid = grp.gr_gid;
+ res->id.idtype = IDMAP_GID;
+ }
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * Name-based mapping
+ *
+ * Case 1: If no rule matches do ephemeral
+ *
+ * Case 2: If rule matches and unixname is "" then return no mapping.
+ *
+ * Case 3: If rule matches and unixname is specified then lookup name
+ * service using the unixname. If unixname not found then return no mapping.
+ *
+ * Case 4: If rule matches and unixname is * then lookup name service
+ * using winname as the unixname. If unixname not found then process
+ * other rules using the lookup order. If no other rule matches then do
+ * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
+ * This allows us to specify a fallback unixname per _domain_ or no mapping
+ * instead of the default behaviour of doing ephemeral mapping.
+ *
+ * Example 1:
+ * *@sfbay == *
+ * If looking up windows users foo@sfbay and foo does not exists in
+ * the name service then foo@sfbay will be mapped to an ephemeral id.
+ *
+ * Example 2:
+ * *@sfbay == *
+ * *@sfbay => guest
+ * If looking up windows users foo@sfbay and foo does not exists in
+ * the name service then foo@sfbay will be mapped to guest.
+ *
+ * Example 3:
+ * *@sfbay == *
+ * *@sfbay => ""
+ * If looking up windows users foo@sfbay and foo does not exists in
+ * the name service then we will return no mapping for foo@sfbay.
+ *
+ */
+static idmap_retcode
+name_based_mapping_sid2pid(sqlite *db, idmap_mapping *req, idmap_id_res *res) {
+ const char *unixname, *winname, *windomain;
+ char *sql = NULL, *errmsg = NULL;
+ idmap_retcode retcode;
+ char *end;
+ const char **values;
+ sqlite_vm *vm = NULL;
+ struct timespec rqtp;
+ idmap_utf8str *str;
+ int ncol, r, i, s, is_user;
+ const char *me = "name_based_mapping_sid2pid";
+
+ winname = req->id1name.idmap_utf8str_val;
+ windomain = req->id1domain.idmap_utf8str_val;
+ is_user = (res->id.idtype == IDMAP_UID)?1:0;
+
+ RDLOCK_CONFIG();
+ i = 0;
+ if (_idmapdstate.cfg->pgcfg.mapping_domain) {
+ if (strcasecmp(_idmapdstate.cfg->pgcfg.mapping_domain,
+ windomain) == 0)
+ i = 1;
+ }
+ UNLOCK_CONFIG();
+
+ sql = sqlite_mprintf(
+ "SELECT unixname, u2w_order FROM namerules WHERE "
+ "w2u_order > 0 AND is_user = %d AND "
+ "(winname = %Q OR winname = '*') AND "
+ "(windomain = %Q OR windomain = '*' %s) "
+ "ORDER BY w2u_order ASC;",
+ is_user, winname, windomain, i?"OR windomain ISNULL":"");
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+
+ if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR,
+ "%s: database error (%s)",
+ me, CHECK_NULL(errmsg));
+ sqlite_freemem(errmsg);
+ goto out;
+ }
+
+ for (i = 0, s = SLEEP_TIME; ; ) {
+ r = sqlite_step(vm, &ncol, &values, NULL);
+
+ if (r == SQLITE_BUSY) {
+ if (++i < MAX_TRIES) {
+ NANO_SLEEP(rqtp, s);
+ s *= 2;
+ continue;
+ }
+ retcode = IDMAP_ERR_BUSY;
+ goto out;
+ } else if (r == SQLITE_ROW) {
+ if (ncol < 2) {
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+ if (values[0] == NULL) {
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+
+ if (EMPTY_NAME(values[0])) {
+ retcode = IDMAP_ERR_NOMAPPING;
+ goto out;
+ }
+ unixname = (values[0][0] == '*')?winname:values[0];
+ retcode = ns_lookup_byname(is_user, unixname, res);
+ if (retcode == IDMAP_ERR_NOTFOUND) {
+ if (unixname == winname)
+ /* Case 4 */
+ continue;
+ else
+ /* Case 3 */
+ retcode = IDMAP_ERR_NOMAPPING;
+ }
+ goto out;
+ } else if (r == SQLITE_DONE) {
+ retcode = IDMAP_ERR_NOTFOUND;
+ goto out;
+ } else {
+ (void) sqlite_finalize(vm, &errmsg);
+ vm = NULL;
+ idmapdlog(LOG_ERR,
+ "%s: database error (%s)",
+ me, CHECK_NULL(errmsg));
+ sqlite_freemem(errmsg);
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+ }
+
+out:
+ if (sql)
+ sqlite_freemem(sql);
+ if (retcode == IDMAP_SUCCESS) {
+ if (values[1])
+ res->direction =
+ (strtol(values[1], &end, 10) == 0)?1:0;
+ else
+ res->direction = 1;
+ str = &req->id2name;
+ retcode = idmap_str2utf8(&str, unixname, 0);
+ }
+ if (vm)
+ (void) sqlite_finalize(vm, NULL);
+ return (retcode);
+}
+
+static
+int
+get_next_eph_uid(uid_t *next_uid)
+{
+ uid_t uid;
+ gid_t gid;
+ int err;
+
+ *next_uid = (uid_t)-1;
+ uid = _idmapdstate.next_uid++;
+ if (uid >= _idmapdstate.limit_uid) {
+ if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0)
+ return (err);
+
+ _idmapdstate.limit_uid = uid + 8192;
+ _idmapdstate.next_uid = uid;
+ }
+ *next_uid = uid;
+
+ return (0);
+}
+
+static
+int
+get_next_eph_gid(gid_t *next_gid)
+{
+ uid_t uid;
+ gid_t gid;
+ int err;
+
+ *next_gid = (uid_t)-1;
+ gid = _idmapdstate.next_gid++;
+ if (gid >= _idmapdstate.limit_gid) {
+ if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0)
+ return (err);
+
+ _idmapdstate.limit_gid = gid + 8192;
+ _idmapdstate.next_gid = gid;
+ }
+ *next_gid = gid;
+
+ return (0);
+}
+
+
+/* ARGSUSED */
+static
+idmap_retcode
+dynamic_ephemeral_mapping(sqlite *cache, idmap_mapping *req,
+ idmap_id_res *res) {
+
+ uid_t next_pid;
+
+ if (IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
+ res->direction = 0;
+ } else if (res->id.idtype == IDMAP_UID) {
+ if (get_next_eph_uid(&next_pid) != 0)
+ return (IDMAP_ERR_INTERNAL);
+ res->id.idmap_id_u.uid = next_pid;
+ res->id.idtype = IDMAP_UID;
+ res->direction = 0;
+ } else {
+ if (get_next_eph_gid(&next_pid) != 0)
+ return (IDMAP_ERR_INTERNAL);
+ res->id.idmap_id_u.gid = next_pid;
+ res->id.idtype = IDMAP_GID;
+ res->direction = 0;
+ }
+
+ return (IDMAP_SUCCESS);
+}
+
+idmap_retcode
+sid2pid_second_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
+ idmap_mapping *req, idmap_id_res *res) {
+ idmap_retcode retcode;
+
+ /*
+ * The req->direction field is used to maintain state of the
+ * sid2pid request.
+ */
+
+ /* Check if second pass is needed */
+ if (req->direction == _IDMAP_F_DONE)
+ return (res->retcode);
+
+ /* Get status from previous pass */
+ retcode = (res->retcode == IDMAP_NEXT)?IDMAP_SUCCESS:res->retcode;
+
+ if (retcode != IDMAP_SUCCESS) {
+ /* Reset return type */
+ res->id.idtype = req->id2.idtype;
+ res->id.idmap_id_u.uid = UID_NOBODY;
+
+ /* Check if this is a localsid */
+ if (retcode == IDMAP_ERR_NOTFOUND &&
+ _idmapdstate.cfg->pgcfg.machine_sid) {
+ retcode = lookup_localsid2pid(req, res);
+ if (retcode == IDMAP_SUCCESS) {
+ state->sid2pid_done = FALSE;
+ req->direction = _IDMAP_F_S2N_CACHE;
+ }
+ goto out;
+ }
+ goto out;
+ }
+
+ /*
+ * Verify that the sid type matches the request if the
+ * SID was validated by an AD lookup.
+ */
+ if (req->direction & _IDMAP_F_S2N_AD) {
+ retcode = verify_type(req->id2.idtype,
+ (int)res->id.idtype, res);
+ if (retcode != IDMAP_SUCCESS) {
+ res->id.idtype = req->id2.idtype;
+ res->id.idmap_id_u.uid = UID_NOBODY;
+ goto out;
+ }
+ }
+
+ /* Name-based mapping */
+ retcode = name_based_mapping_sid2pid(db, req, res);
+ if (retcode == IDMAP_ERR_NOTFOUND)
+ /* If not found, do ephemeral mapping */
+ goto ephemeral;
+ else if (retcode != IDMAP_SUCCESS)
+ goto out;
+
+ state->sid2pid_done = FALSE;
+ goto out;
+
+
+ephemeral:
+ retcode = dynamic_ephemeral_mapping(cache, req, res);
+ if (retcode == IDMAP_SUCCESS)
+ state->sid2pid_done = FALSE;
+
+out:
+ res->retcode = idmap_stat4prot(retcode);
+ return (retcode);
+}
+
+idmap_retcode
+update_cache_pid2sid(lookup_state_t *state, sqlite *cache,
+ idmap_mapping *req, idmap_id_res *res) {
+ char *sql = NULL;
+ idmap_retcode retcode;
+
+ /* Check if we need to cache anything */
+ if (req->direction == _IDMAP_F_DONE)
+ return (IDMAP_SUCCESS);
+
+ /* We don't cache negative entries */
+ if (res->retcode != IDMAP_SUCCESS)
+ return (IDMAP_SUCCESS);
+
+ /*
+ * Using NULL for u2w instead of 0 so that our trigger allows
+ * the same pid to be the destination in multiple entries
+ */
+ sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
+ "(sidprefix, rid, windomain, winname, pid, unixname, "
+ "is_user, expiration, w2u, u2w) "
+ "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
+ "strftime('%%s','now') + 600, %q, 1); ",
+ res->id.idmap_id_u.sid.prefix,
+ res->id.idmap_id_u.sid.rid,
+ req->id2domain.idmap_utf8str_val,
+ req->id2name.idmap_utf8str_val,
+ req->id1.idmap_id_u.uid,
+ req->id1name.idmap_utf8str_val,
+ (req->id1.idtype == IDMAP_UID)?1:0,
+ (res->direction == 0)?"1":NULL);
+
+ if (sql == NULL) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ retcode = sql_exec_no_cb(cache, sql);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+
+ state->pid2sid_done = FALSE;
+ sqlite_freemem(sql);
+ sql = NULL;
+
+ /* If sid2name was found in the cache, no need to update namecache */
+ if (req->direction & _IDMAP_F_S2N_CACHE)
+ goto out;
+
+ if (req->id2name.idmap_utf8str_val == NULL)
+ goto out;
+
+ sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
+ "(sidprefix, rid, name, domain, type, expiration) "
+ "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
+ res->id.idmap_id_u.sid.prefix,
+ res->id.idmap_id_u.sid.rid,
+ req->id2name.idmap_utf8str_val,
+ req->id2domain.idmap_utf8str_val,
+ (req->id1.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
+
+ if (sql == NULL) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ retcode = sql_exec_no_cb(cache, sql);
+
+out:
+ if (sql)
+ sqlite_freemem(sql);
+ return (retcode);
+}
+
+idmap_retcode
+update_cache_sid2pid(lookup_state_t *state, sqlite *cache,
+ idmap_mapping *req, idmap_id_res *res) {
+ char *sql = NULL;
+ idmap_retcode retcode;
+ int is_eph_user;
+
+ /* Check if we need to cache anything */
+ if (req->direction == _IDMAP_F_DONE)
+ return (IDMAP_SUCCESS);
+
+ /* We don't cache negative entries */
+ if (res->retcode != IDMAP_SUCCESS)
+ return (IDMAP_SUCCESS);
+
+ if (req->direction & _IDMAP_F_EXP_EPH_UID)
+ is_eph_user = 1;
+ else if (req->direction & _IDMAP_F_EXP_EPH_GID)
+ is_eph_user = 0;
+ else
+ is_eph_user = -1;
+
+ if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
+ sql = sqlite_mprintf("UPDATE idmap_cache "
+ "SET w2u = 0 WHERE "
+ "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
+ "pid >= 2147483648 AND is_user = %d;",
+ req->id1.idmap_id_u.sid.prefix,
+ req->id1.idmap_id_u.sid.rid,
+ is_eph_user);
+ if (sql == NULL) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ retcode = sql_exec_no_cb(cache, sql);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+
+ sqlite_freemem(sql);
+ sql = NULL;
+ }
+
+ sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
+ "(sidprefix, rid, windomain, winname, pid, unixname, "
+ "is_user, expiration, w2u, u2w) "
+ "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
+ "strftime('%%s','now') + 600, 1, %q); ",
+ req->id1.idmap_id_u.sid.prefix,
+ req->id1.idmap_id_u.sid.rid,
+ req->id1domain.idmap_utf8str_val,
+ req->id1name.idmap_utf8str_val,
+ res->id.idmap_id_u.uid,
+ req->id2name.idmap_utf8str_val,
+ (res->id.idtype == IDMAP_UID)?1:0,
+ (res->direction == 0)?"1":NULL);
+
+ if (sql == NULL) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ retcode = sql_exec_no_cb(cache, sql);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+
+ state->sid2pid_done = FALSE;
+ sqlite_freemem(sql);
+ sql = NULL;
+
+ /* If name2sid was found in the cache, no need to update namecache */
+ if (req->direction & _IDMAP_F_S2N_CACHE)
+ goto out;
+
+ if (req->id1name.idmap_utf8str_val == NULL)
+ goto out;
+
+ sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
+ "(sidprefix, rid, name, domain, type, expiration) "
+ "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
+ req->id1.idmap_id_u.sid.prefix,
+ req->id1.idmap_id_u.sid.rid,
+ req->id1name.idmap_utf8str_val,
+ req->id1domain.idmap_utf8str_val,
+ (res->id.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
+
+ if (sql == NULL) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ retcode = sql_exec_no_cb(cache, sql);
+
+out:
+ if (sql)
+ sqlite_freemem(sql);
+ return (retcode);
+}
+
+static idmap_retcode
+lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
+ int is_user, int getname) {
+ char *end;
+ char *sql = NULL;
+ const char **values;
+ sqlite_vm *vm = NULL;
+ int ncol;
+ idmap_retcode retcode = IDMAP_SUCCESS;
+ idmap_utf8str *str;
+ time_t curtime;
+
+ /* Current time */
+ errno = 0;
+ if ((curtime = time(NULL)) == (time_t)-1) {
+ idmapdlog(LOG_ERR,
+ "Failed to get current time (%s)",
+ strerror(errno));
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+
+ /* SQL to lookup the cache */
+ sql = sqlite_mprintf("SELECT sidprefix, rid, winname, windomain, w2u "
+ "FROM idmap_cache WHERE "
+ "pid = %u AND u2w = 1 AND is_user = %d AND "
+ "(pid >= 2147483648 OR "
+ "(expiration = 0 OR expiration ISNULL OR "
+ "expiration > %d));",
+ req->id1.idmap_id_u.uid, is_user, curtime);
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
+ sqlite_freemem(sql);
+
+ if (retcode == IDMAP_ERR_NOTFOUND)
+ goto out;
+ else if (retcode == IDMAP_SUCCESS) {
+ /* sanity checks */
+ if (values[0] == NULL || values[1] == NULL) {
+ retcode = IDMAP_ERR_CACHE;
+ goto out;
+ }
+
+ switch (req->id2.idtype) {
+ case IDMAP_SID:
+ res->id.idmap_id_u.sid.rid =
+ strtoul(values[1], &end, 10);
+ res->id.idmap_id_u.sid.prefix = strdup(values[0]);
+ if (res->id.idmap_id_u.sid.prefix == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+
+ if (values[4])
+ res->direction =
+ (strtol(values[4], &end, 10) == 0)?2:0;
+ else
+ res->direction = 2;
+
+ if (getname == 0 || values[2] == NULL)
+ break;
+ str = &req->id2name;
+ retcode = idmap_str2utf8(&str, values[2], 0);
+ if (retcode != IDMAP_SUCCESS) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+
+ if (values[3] == NULL)
+ break;
+ str = &req->id2domain;
+ retcode = idmap_str2utf8(&str, values[3], 0);
+ if (retcode != IDMAP_SUCCESS) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ break;
+ default:
+ retcode = IDMAP_ERR_NOTSUPPORTED;
+ break;
+ }
+ }
+
+out:
+ if (vm)
+ (void) sqlite_finalize(vm, NULL);
+ return (retcode);
+}
+
+static idmap_retcode
+lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain,
+ char **sidprefix, idmap_rid_t *rid, int *type) {
+ char *end;
+ char *sql = NULL;
+ const char **values;
+ sqlite_vm *vm = NULL;
+ int ncol;
+ time_t curtime;
+ idmap_retcode retcode = IDMAP_SUCCESS;
+
+ /* Get current time */
+ errno = 0;
+ if ((curtime = time(NULL)) == (time_t)-1) {
+ idmapdlog(LOG_ERR,
+ "Failed to get current time (%s)",
+ strerror(errno));
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+
+ /* SQL to lookup the cache */
+ sql = sqlite_mprintf("SELECT sidprefix, rid, type FROM name_cache "
+ "WHERE name = %Q AND domain = %Q AND "
+ "(expiration = 0 OR expiration ISNULL OR "
+ "expiration > %d);",
+ name, domain, curtime);
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
+ sqlite_freemem(sql);
+
+ if (retcode == IDMAP_SUCCESS) {
+ if (type) {
+ if (values[2] == NULL) {
+ retcode = IDMAP_ERR_CACHE;
+ goto out;
+ }
+ *type = strtol(values[2], &end, 10);
+ }
+
+ if (values[0] == NULL || values[1] == NULL) {
+ retcode = IDMAP_ERR_CACHE;
+ goto out;
+ }
+ if ((*sidprefix = strdup(values[0])) == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ *rid = strtoul(values[1], &end, 10);
+ }
+
+out:
+ if (vm)
+ (void) sqlite_finalize(vm, NULL);
+ return (retcode);
+}
+
+static idmap_retcode
+lookup_win_name2sid(const char *name, const char *domain, char **sidprefix,
+ idmap_rid_t *rid, int *type) {
+ int ret;
+ int retries = 0;
+ idmap_query_state_t *qs = NULL;
+ idmap_retcode rc, retcode;
+
+ retcode = IDMAP_ERR_NOTFOUND;
+
+retry:
+ ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
+ if (ret != 0) {
+ idmapdlog(LOG_ERR,
+ "Failed to create name2sid batch for AD lookup");
+ return (IDMAP_ERR_INTERNAL);
+ }
+
+ retcode = idmap_name2sid_batch_add1(qs, name, domain, sidprefix,
+ rid, type, &rc);
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
+ goto out;
+
+ if (retcode != IDMAP_SUCCESS) {
+ idmapdlog(LOG_ERR,
+ "Failed to batch name2sid for AD lookup");
+ idmap_lookup_free_batch(&qs);
+ return (IDMAP_ERR_INTERNAL);
+ }
+
+out:
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
+ idmap_lookup_free_batch(&qs);
+ else
+ retcode = idmap_lookup_batch_end(&qs, NULL);
+
+ if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
+ goto retry;
+
+ if (retcode != IDMAP_SUCCESS) {
+ idmapdlog(LOG_NOTICE, "Windows user/group name to SID lookup "
+ "failed");
+ return (retcode);
+ } else
+ return (rc);
+ /* NOTREACHED */
+}
+
+static idmap_retcode
+lookup_name2sid(sqlite *cache, const char *name, const char *domain,
+ int *is_user, char **sidprefix, idmap_rid_t *rid,
+ idmap_mapping *req) {
+ int type;
+ idmap_retcode retcode;
+
+ /* Lookup sid to name@domain in cache */
+ retcode = lookup_cache_name2sid(cache, name, domain, sidprefix,
+ rid, &type);
+ if (retcode == IDMAP_ERR_NOTFOUND) {
+ /* Lookup Windows NT/AD to map name@domain to sid */
+ retcode = lookup_win_name2sid(name, domain, sidprefix, rid,
+ &type);
+ if (retcode != IDMAP_SUCCESS)
+ return (retcode);
+ req->direction |= _IDMAP_F_S2N_AD;
+ } else if (retcode != IDMAP_SUCCESS) {
+ return (retcode);
+ } else {
+ /* Set flag */
+ req->direction |= _IDMAP_F_S2N_CACHE;
+ }
+
+ /*
+ * Entry found (cache or Windows lookup)
+ * is_user is both input as well as output parameter
+ */
+ if (*is_user == 1) {
+ if (type != _IDMAP_T_USER)
+ return (IDMAP_ERR_NOTUSER);
+ } else if (*is_user == 0) {
+ if (type != _IDMAP_T_GROUP)
+ return (IDMAP_ERR_NOTGROUP);
+ } else if (*is_user == -1) {
+ /* Caller wants to know if its user or group */
+ if (type == _IDMAP_T_USER)
+ *is_user = 1;
+ else if (type == _IDMAP_T_GROUP)
+ *is_user = 0;
+ else
+ return (IDMAP_ERR_SID);
+ }
+
+ return (retcode);
+}
+
+static idmap_retcode
+name_based_mapping_pid2sid(sqlite *db, sqlite *cache, const char *unixname,
+ int is_user, idmap_mapping *req, idmap_id_res *res) {
+ const char *winname, *windomain;
+ char *mapping_domain = NULL;
+ char *sql = NULL, *errmsg = NULL;
+ idmap_retcode retcode;
+ char *end;
+ const char **values;
+ sqlite_vm *vm = NULL;
+ idmap_utf8str *str;
+ struct timespec rqtp;
+ int ncol, r, i, s;
+ const char *me = "name_based_mapping_pid2sid";
+
+ RDLOCK_CONFIG();
+ if (_idmapdstate.cfg->pgcfg.mapping_domain) {
+ mapping_domain =
+ strdup(_idmapdstate.cfg->pgcfg.mapping_domain);
+ if (mapping_domain == NULL) {
+ UNLOCK_CONFIG();
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ }
+ UNLOCK_CONFIG();
+
+ sql = sqlite_mprintf(
+ "SELECT winname, windomain, w2u_order FROM namerules WHERE "
+ "u2w_order > 0 AND is_user = %d AND "
+ "(unixname = %Q OR unixname = '*') "
+ "ORDER BY u2w_order ASC;",
+ is_user, unixname);
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+
+ if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
+ retcode = IDMAP_ERR_INTERNAL;
+ idmapdlog(LOG_ERR,
+ "%s: database error (%s)",
+ me, CHECK_NULL(errmsg));
+ sqlite_freemem(errmsg);
+ goto out;
+ }
+
+ for (i = 0, s = SLEEP_TIME; ; ) {
+ r = sqlite_step(vm, &ncol, &values, NULL);
+ if (r == SQLITE_BUSY) {
+ if (++i < MAX_TRIES) {
+ NANO_SLEEP(rqtp, s);
+ s *= 2;
+ continue;
+ }
+ retcode = IDMAP_ERR_BUSY;
+ goto out;
+ } else if (r == SQLITE_ROW) {
+ if (ncol < 3) {
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+ if (values[0] == NULL) {
+ /* values [1] and [2] can be null */
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+ if (EMPTY_NAME(values[0])) {
+ retcode = IDMAP_ERR_NOMAPPING;
+ goto out;
+ }
+ winname = (values[0][0] == '*')?unixname:values[0];
+ if (values[1])
+ windomain = values[1];
+ else if (mapping_domain)
+ windomain = mapping_domain;
+ else {
+ idmapdlog(LOG_ERR,
+ "%s: no domain", me);
+ retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
+ goto out;
+ }
+ /* Lookup winname@domain to sid */
+ retcode = lookup_name2sid(cache, winname, windomain,
+ &is_user, &res->id.idmap_id_u.sid.prefix,
+ &res->id.idmap_id_u.sid.rid, req);
+ if (retcode == IDMAP_ERR_NOTFOUND) {
+ if (winname == unixname)
+ continue;
+ else
+ retcode = IDMAP_ERR_NOMAPPING;
+ }
+ goto out;
+ } else if (r == SQLITE_DONE) {
+ retcode = IDMAP_ERR_NOTFOUND;
+ goto out;
+ } else {
+ (void) sqlite_finalize(vm, &errmsg);
+ vm = NULL;
+ idmapdlog(LOG_ERR,
+ "%s: database error (%s)",
+ me, CHECK_NULL(errmsg));
+ sqlite_freemem(errmsg);
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+ }
+
+out:
+ if (sql)
+ sqlite_freemem(sql);
+ if (retcode == IDMAP_SUCCESS) {
+ if (values[2])
+ res->direction =
+ (strtol(values[2], &end, 10) == 0)?2:0;
+ else
+ res->direction = 2;
+ str = &req->id2name;
+ retcode = idmap_str2utf8(&str, winname, 0);
+ if (retcode == IDMAP_SUCCESS) {
+ str = &req->id2domain;
+ if (windomain == mapping_domain) {
+ (void) idmap_str2utf8(&str, windomain, 1);
+ mapping_domain = NULL;
+ } else
+ retcode = idmap_str2utf8(&str, windomain, 0);
+ }
+ }
+ if (vm)
+ (void) sqlite_finalize(vm, NULL);
+ if (mapping_domain)
+ free(mapping_domain);
+ return (retcode);
+}
+
+idmap_retcode
+pid2sid_first_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
+ idmap_mapping *req, idmap_id_res *res, int is_user,
+ int getname) {
+ char *unixname = NULL;
+ struct passwd pwd;
+ struct group grp;
+ idmap_utf8str *str;
+ char buf[1024];
+ int errnum;
+ idmap_retcode retcode = IDMAP_SUCCESS;
+ const char *me = "pid2sid";
+
+ req->direction = _IDMAP_F_DONE;
+ res->id.idtype = req->id2.idtype;
+
+ /* Lookup well-known SIDs */
+ retcode = lookup_wksids_pid2sid(req, res, is_user);
+ if (retcode != IDMAP_ERR_NOTFOUND)
+ goto out;
+
+ /* Lookup pid to sid in cache */
+ retcode = lookup_cache_pid2sid(cache, req, res, is_user, getname);
+ if (retcode != IDMAP_ERR_NOTFOUND)
+ goto out;
+
+ /* Ephemeral ids cannot be allocated during pid2sid */
+ if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) {
+ retcode = IDMAP_ERR_NOTFOUND;
+ goto out;
+ }
+
+ if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
+ retcode = IDMAP_ERR_NOTFOUND;
+ goto out;
+ }
+
+ /* uid/gid to name */
+ if (req->id1name.idmap_utf8str_val) {
+ unixname = req->id1name.idmap_utf8str_val;
+ } if (is_user) {
+ errno = 0;
+ if (getpwuid_r(req->id1.idmap_id_u.uid, &pwd, buf,
+ sizeof (buf)) == NULL) {
+ errnum = errno;
+ idmapdlog(LOG_WARNING,
+ "%s: getpwuid_r(%u) failed (%s).",
+ me, req->id1.idmap_id_u.uid,
+ errnum?strerror(errnum):"not found");
+ retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
+ IDMAP_ERR_INTERNAL;
+ goto fallback_localsid;
+ }
+ unixname = pwd.pw_name;
+ } else {
+ errno = 0;
+ if (getgrgid_r(req->id1.idmap_id_u.gid, &grp, buf,
+ sizeof (buf)) == NULL) {
+ errnum = errno;
+ idmapdlog(LOG_WARNING,
+ "%s: getgrgid_r(%u) failed (%s).",
+ me, req->id1.idmap_id_u.gid,
+ errnum?strerror(errnum):"not found");
+ retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
+ IDMAP_ERR_INTERNAL;
+ goto fallback_localsid;
+ }
+ unixname = grp.gr_name;
+ }
+
+ /* Name-based mapping */
+ retcode = name_based_mapping_pid2sid(db, cache, unixname, is_user,
+ req, res);
+ if (retcode == IDMAP_ERR_NOTFOUND) {
+ retcode = generate_localsid(req, res, is_user);
+ goto out;
+ } else if (retcode == IDMAP_SUCCESS)
+ goto out;
+
+fallback_localsid:
+ /*
+ * Here we generate localsid as fallback id on errors. Our
+ * return status is the error that's been previously assigned.
+ */
+ (void) generate_localsid(req, res, is_user);
+
+out:
+ if (retcode == IDMAP_SUCCESS) {
+ if (req->id1name.idmap_utf8str_val == NULL && unixname) {
+ str = &req->id1name;
+ retcode = idmap_str2utf8(&str, unixname, 0);
+ }
+ }
+ if (req->direction != _IDMAP_F_DONE)
+ state->pid2sid_done = FALSE;
+ res->retcode = idmap_stat4prot(retcode);
+ return (retcode);
+}
+
+static idmap_retcode
+lookup_win_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
+ char **domain, int *type) {
+ int ret;
+ idmap_query_state_t *qs = NULL;
+ idmap_retcode rc, retcode;
+
+ retcode = IDMAP_ERR_NOTFOUND;
+
+ ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
+ if (ret != 0) {
+ idmapdlog(LOG_ERR,
+ "Failed to create sid2name batch for AD lookup");
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+
+ ret = idmap_sid2name_batch_add1(
+ qs, sidprefix, &rid, name, domain, type, &rc);
+ if (ret != 0) {
+ idmapdlog(LOG_ERR,
+ "Failed to batch sid2name for AD lookup");
+ retcode = IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+
+out:
+ if (qs) {
+ ret = idmap_lookup_batch_end(&qs, NULL);
+ if (ret != 0) {
+ idmapdlog(LOG_ERR,
+ "Failed to execute sid2name AD lookup");
+ retcode = IDMAP_ERR_INTERNAL;
+ } else
+ retcode = rc;
+ }
+
+ return (retcode);
+}
+
+static void
+copy_id_mapping(idmap_mapping *mapping, idmap_mapping *request)
+{
+ mapping->flag = request->flag;
+ mapping->direction = request->direction;
+
+ mapping->id1.idtype = request->id1.idtype;
+ if (request->id1.idtype == IDMAP_SID) {
+ mapping->id1.idmap_id_u.sid.rid =
+ request->id1.idmap_id_u.sid.rid;
+ if (request->id1.idmap_id_u.sid.prefix)
+ mapping->id1.idmap_id_u.sid.prefix =
+ strdup(request->id1.idmap_id_u.sid.prefix);
+ else
+ mapping->id1.idmap_id_u.sid.prefix = NULL;
+ } else {
+ mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid;
+ }
+
+ mapping->id1domain.idmap_utf8str_len =
+ request->id1domain.idmap_utf8str_len;
+ if (mapping->id1domain.idmap_utf8str_len)
+ mapping->id1domain.idmap_utf8str_val =
+ strdup(request->id1domain.idmap_utf8str_val);
+ else
+ mapping->id1domain.idmap_utf8str_val = NULL;
+
+ mapping->id1name.idmap_utf8str_len =
+ request->id1name.idmap_utf8str_len;
+ if (mapping->id1name.idmap_utf8str_len)
+ mapping->id1name.idmap_utf8str_val =
+ strdup(request->id1name.idmap_utf8str_val);
+ else
+ mapping->id1name.idmap_utf8str_val = NULL;
+
+ mapping->id2.idtype = request->id2.idtype;
+ if (request->id2.idtype == IDMAP_SID) {
+ mapping->id2.idmap_id_u.sid.rid =
+ request->id2.idmap_id_u.sid.rid;
+ if (request->id2.idmap_id_u.sid.prefix)
+ mapping->id2.idmap_id_u.sid.prefix =
+ strdup(request->id2.idmap_id_u.sid.prefix);
+ else
+ mapping->id2.idmap_id_u.sid.prefix = NULL;
+ } else {
+ mapping->id2.idmap_id_u.uid = request->id2.idmap_id_u.uid;
+ }
+
+ mapping->id2domain.idmap_utf8str_len =
+ request->id2domain.idmap_utf8str_len;
+ if (mapping->id2domain.idmap_utf8str_len)
+ mapping->id2domain.idmap_utf8str_val =
+ strdup(request->id2domain.idmap_utf8str_val);
+ else
+ mapping->id2domain.idmap_utf8str_val = NULL;
+
+ mapping->id2name.idmap_utf8str_len =
+ request->id2name.idmap_utf8str_len;
+ if (mapping->id2name.idmap_utf8str_len)
+ mapping->id2name.idmap_utf8str_val =
+ strdup(request->id2name.idmap_utf8str_val);
+ else
+ mapping->id2name.idmap_utf8str_val = NULL;
+}
+
+
+idmap_retcode
+get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
+ idmap_mapping *mapping) {
+ idmap_id_res idres;
+ lookup_state_t state;
+ idmap_utf8str *str;
+ int is_user;
+ idmap_retcode retcode;
+ const char *winname, *windomain;
+
+ (void) memset(&idres, 0, sizeof (idres));
+ (void) memset(&state, 0, sizeof (state));
+
+ if (request->id2.idtype == IDMAP_UID)
+ is_user = 1;
+ else if (request->id2.idtype == IDMAP_GID)
+ is_user = 0;
+ else if (request->id2.idtype == IDMAP_POSIXID)
+ is_user = -1;
+ else {
+ retcode = IDMAP_ERR_IDTYPE;
+ goto out;
+ }
+
+ /* Copy data from request to result */
+ copy_id_mapping(mapping, request);
+
+ winname = mapping->id1name.idmap_utf8str_val;
+ windomain = mapping->id1domain.idmap_utf8str_val;
+
+ if (winname == NULL && windomain) {
+ retcode = IDMAP_ERR_ARG;
+ goto out;
+ }
+
+ if (winname && windomain == NULL) {
+ str = &mapping->id1domain;
+ RDLOCK_CONFIG();
+ if (_idmapdstate.cfg->pgcfg.mapping_domain) {
+ retcode = idmap_str2utf8(&str,
+ _idmapdstate.cfg->pgcfg.mapping_domain, 0);
+ if (retcode != IDMAP_SUCCESS) {
+ UNLOCK_CONFIG();
+ idmapdlog(LOG_ERR, "Out of memory");
+ retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ }
+ UNLOCK_CONFIG();
+ windomain = mapping->id1domain.idmap_utf8str_val;
+ }
+
+ if (winname && EMPTY_STRING(mapping->id1.idmap_id_u.sid.prefix)) {
+ retcode = lookup_name2sid(cache, winname, windomain,
+ &is_user, &mapping->id1.idmap_id_u.sid.prefix,
+ &mapping->id1.idmap_id_u.sid.rid, mapping);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+ if (mapping->id2.idtype == IDMAP_POSIXID)
+ mapping->id2.idtype = is_user?IDMAP_UID:IDMAP_GID;
+ }
+
+ state.sid2pid_done = TRUE;
+ retcode = sid2pid_first_pass(&state, cache, mapping, &idres);
+ if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
+ goto out;
+
+ if (state.ad_nqueries) {
+ /* sid2name AD lookup */
+ retcode = lookup_win_sid2name(
+ mapping->id1.idmap_id_u.sid.prefix,
+ mapping->id1.idmap_id_u.sid.rid,
+ &mapping->id1name.idmap_utf8str_val,
+ &mapping->id1domain.idmap_utf8str_val,
+ (int *)&idres.id.idtype);
+
+ idres.retcode = retcode;
+ }
+
+ state.sid2pid_done = TRUE;
+ retcode = sid2pid_second_pass(&state, cache, db, mapping, &idres);
+ if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
+ goto out;
+
+ /* Update cache */
+ (void) update_cache_sid2pid(&state, cache, mapping, &idres);
+
+out:
+ if (retcode == IDMAP_SUCCESS) {
+ mapping->direction = idres.direction;
+ mapping->id2 = idres.id;
+ (void) memset(&idres, 0, sizeof (idres));
+ }
+ xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
+ return (retcode);
+}
+
+idmap_retcode
+get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
+ idmap_mapping *mapping, int is_user) {
+ idmap_id_res idres;
+ lookup_state_t state;
+ struct passwd pwd;
+ struct group grp;
+ char buf[1024];
+ int errnum;
+ idmap_retcode retcode;
+ const char *unixname;
+ const char *me = "get_u2w_mapping";
+
+ /*
+ * In order to re-use the pid2sid code, we convert
+ * our input data into structs that are expected by
+ * pid2sid_first_pass.
+ */
+
+ (void) memset(&idres, 0, sizeof (idres));
+ (void) memset(&state, 0, sizeof (state));
+
+ /* Copy data from request to result */
+ copy_id_mapping(mapping, request);
+
+ unixname = mapping->id1name.idmap_utf8str_val;
+
+ if (unixname == NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
+ retcode = IDMAP_ERR_ARG;
+ goto out;
+ }
+
+ if (unixname && mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
+ /* Get uid/gid by name */
+ if (is_user) {
+ errno = 0;
+ if (getpwnam_r(unixname, &pwd, buf,
+ sizeof (buf)) == NULL) {
+ errnum = errno;
+ idmapdlog(LOG_WARNING,
+ "%s: getpwnam_r(%s) failed (%s).",
+ me, unixname,
+ errnum?strerror(errnum):"not found");
+ retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
+ IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+ mapping->id1.idmap_id_u.uid = pwd.pw_uid;
+ } else {
+ errno = 0;
+ if (getgrnam_r(unixname, &grp, buf,
+ sizeof (buf)) == NULL) {
+ errnum = errno;
+ idmapdlog(LOG_WARNING,
+ "%s: getgrnam_r(%s) failed (%s).",
+ me, unixname,
+ errnum?strerror(errnum):"not found");
+ retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
+ IDMAP_ERR_INTERNAL;
+ goto out;
+ }
+ mapping->id1.idmap_id_u.gid = grp.gr_gid;
+ }
+ }
+
+ state.pid2sid_done = TRUE;
+ retcode = pid2sid_first_pass(&state, cache, db, mapping, &idres,
+ is_user, 1);
+ if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE)
+ goto out;
+
+ /* Update cache */
+ (void) update_cache_pid2sid(&state, cache, mapping, &idres);
+
+out:
+ mapping->direction = idres.direction;
+ mapping->id2 = idres.id;
+ (void) memset(&idres, 0, sizeof (idres));
+ xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
+ return (retcode);
+}
diff --git a/usr/src/cmd/idmap/idmapd/idmap.xml b/usr/src/cmd/idmap/idmapd/idmap.xml
new file mode 100644
index 0000000000..2b674b5c5f
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/idmap.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWcsr:idmap'>
+
+<service
+ name='system/idmap'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <single_instance />
+
+ <dependency
+ name='rpcbind'
+ grouping='require_all'
+ restart_on='restart'
+ type='service'>
+ <service_fmri value='svc:/network/rpc/bind' />
+ </dependency>
+
+ <dependency name='filesystem-minimal'
+ grouping='require_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/usr/lib/idmapd'
+ timeout_seconds='60' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <exec_method
+ type='method'
+ name='refresh'
+ exec=':kill -HUP'
+ timeout_seconds='60' />
+
+ <property_group name='general' type='framework'>
+ <propval
+ name='action_authorization'
+ type='astring'
+ value='solaris.smf.manage.idmap' />
+ </property_group>
+
+<!--
+ Properties affecting the service
+-->
+ <property_group name='config' type='application' >
+ <stability value='Unstable' />
+ <propval
+ name='list_size_limit'
+ type='count'
+ value='0' />
+ <propval
+ name='value_authorization'
+ type='astring'
+ value='solaris.smf.value.idmap' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Native Identity Mapping Service
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='idmapd' section='1M'
+ manpath='/usr/share/man' />
+ <manpage title='idmap' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.c b/usr/src/cmd/idmap/idmapd/idmap_config.c
new file mode 100644
index 0000000000..f92ef2edf4
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.c
@@ -0,0 +1,389 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Config routines common to idmap(1M) and idmapd(1M)
+ */
+
+#include <stdlib.h>
+#include <synch.h>
+#include <assert.h>
+#include <sys/varargs.h>
+#include <sys/systeminfo.h>
+#include <strings.h>
+#include <libintl.h>
+#include <ctype.h>
+#include <errno.h>
+#include "idmap_config.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+#define FMRI_BASE "svc:/system/idmap"
+
+#define CONFIG_PG "config"
+#define GENERAL_PG "general"
+
+#define IDMAP_CFG_DEBUG 0
+
+/* initial length of the array for policy options/attributes: */
+#define DEF_ARRAY_LENGTH 16
+
+static char errmess_buf [1000] =
+ "Internal error: idmap configuration has not been initialized";
+
+static void
+errmess(char *format, va_list ap)
+{
+/*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ (void) vsnprintf(errmess_buf, sizeof (errmess_buf), format, ap);
+ (void) strlcat(errmess_buf, gettext(".\n"), sizeof (errmess_buf));
+
+#if IDMAP_CFG_DEBUG
+ (void) fprintf(stderr, errmess_buf);
+ fflush(stderr);
+#endif
+}
+
+
+static void
+idmap_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ errmess(format, ap);
+ va_end(ap);
+}
+
+static void
+idmap_scf_error(char *format, ...)
+{
+ const char *scf_message;
+ char *new_format;
+ char *sep;
+ va_list ap;
+
+ sep = gettext(": ");
+ va_start(ap, format);
+
+ scf_message = scf_strerror(scf_error());
+ new_format = (char *) malloc(sizeof (char) *
+ (strlen(format) + strlen(scf_message) + strlen(sep) + 1));
+
+ (void) strcpy(new_format, format);
+ (void) strcat(new_format, sep);
+ (void) strcat(new_format, scf_message);
+
+ errmess(new_format, ap);
+
+ va_end(ap);
+ free(new_format);
+}
+
+char *
+idmap_cfg_error() {
+ return (errmess_buf);
+}
+
+/* Check if in the case of failure the original value of *val is preserved */
+static int
+get_val_int(idmap_cfg_t *cfg, char *name, void *val, scf_type_t type)
+{
+ int rc = 0;
+
+ scf_property_t *scf_prop = scf_property_create(cfg->handles.main);
+ scf_value_t *value = scf_value_create(cfg->handles.main);
+
+
+ if (0 > scf_pg_get_property(cfg->handles.config_pg, name, scf_prop))
+ /* this is OK: the property is just undefined */
+ goto destruction;
+
+
+ if (0 > scf_property_get_value(scf_prop, value))
+ /* It is still OK when a property doesn't have any value */
+ goto destruction;
+
+ switch (type) {
+ case SCF_TYPE_BOOLEAN:
+ rc = scf_value_get_boolean(value, val);
+ break;
+ case SCF_TYPE_COUNT:
+ rc = scf_value_get_count(value, val);
+ break;
+ case SCF_TYPE_INTEGER:
+ rc = scf_value_get_integer(value, val);
+ break;
+ default:
+ idmap_scf_error(gettext("Internal error: invalid int type %d"),
+ type);
+ rc = -1;
+ break;
+ }
+
+
+destruction:
+ scf_value_destroy(value);
+ scf_property_destroy(scf_prop);
+
+ return (rc);
+}
+
+static char *
+scf_value2string(scf_value_t *value) {
+ int rc = -1;
+ char buf_size = 127;
+ int length;
+ char *buf = NULL;
+ buf = (char *) malloc(sizeof (char) * buf_size);
+
+ for (;;) {
+ length = scf_value_get_astring(value, buf, buf_size);
+ if (length < 0) {
+ rc = -1;
+ goto destruction;
+ }
+
+ if (length == buf_size - 1) {
+ buf_size *= 2;
+ buf = (char *)realloc(buf, buf_size * sizeof (char));
+ if (!buf) {
+ idmap_scf_error(
+ gettext("Not enough memory"));
+ rc = -1;
+ goto destruction;
+ }
+ } else {
+ rc = 0;
+ break;
+ }
+ }
+
+destruction:
+ if (rc < 0) {
+ if (buf)
+ free(buf);
+ buf = NULL;
+ }
+
+ return (buf);
+}
+
+
+static int
+get_val_astring(idmap_cfg_t *cfg, char *name, char **val)
+{
+ int rc = 0;
+
+ scf_property_t *scf_prop = scf_property_create(cfg->handles.main);
+ scf_value_t *value = scf_value_create(cfg->handles.main);
+
+
+ if (0 > scf_pg_get_property(cfg->handles.config_pg, name, scf_prop))
+ /* this is OK: the property is just undefined */
+ goto destruction;
+
+ if (0 > scf_property_get_value(scf_prop, value)) {
+ idmap_scf_error(gettext("Cannot get the astring %s"), name);
+ rc = -1;
+ goto destruction;
+ }
+
+ if (!(*val = scf_value2string(value))) {
+ rc = -1;
+ idmap_scf_error(gettext("Cannot retrieve the astring %s"),
+ name);
+ }
+
+destruction:
+ scf_value_destroy(value);
+ scf_property_destroy(scf_prop);
+
+ if (rc < 0) {
+ if (*val)
+ free(*val);
+ *val = NULL;
+ }
+
+ return (rc);
+}
+
+int
+idmap_cfg_load(idmap_cfg_t *cfg)
+{
+ int rc = 0;
+
+ cfg->pgcfg.list_size_limit = 0;
+ cfg->pgcfg.mapping_domain = NULL;
+ cfg->pgcfg.machine_sid = NULL;
+ cfg->pgcfg.domain_controller = NULL;
+ cfg->pgcfg.global_catalog = NULL;
+
+ if (0 > scf_pg_update(cfg->handles.config_pg)) {
+ idmap_scf_error(gettext("Error updating config pg"));
+ return (-1);
+ }
+
+ if (0 > scf_pg_update(cfg->handles.general_pg)) {
+ idmap_scf_error(gettext("Error updating general pg"));
+ return (-1);
+ }
+
+ rc = get_val_int(cfg, "list_size_limit",
+ &cfg->pgcfg.list_size_limit, SCF_TYPE_COUNT);
+ if (rc != 0)
+ return (-1);
+
+ rc = get_val_astring(cfg, "mapping_domain",
+ &cfg->pgcfg.mapping_domain);
+ if (rc != 0)
+ return (-1);
+
+ /*
+ * TBD:
+ * If there is no mapping_domain in idmap's smf config then
+ * set it to the joined domain.
+ * Till domain join is implemented, temporarily set it to
+ * the system domain for testing purposes.
+ */
+ if (!cfg->pgcfg.mapping_domain) {
+ char test[1];
+ long dname_size = sysinfo(SI_SRPC_DOMAIN, test, 1);
+ if (dname_size > 0) {
+ cfg->pgcfg.mapping_domain =
+ (char *)malloc(dname_size * sizeof (char));
+ dname_size = sysinfo(SI_SRPC_DOMAIN,
+ cfg->pgcfg.mapping_domain, dname_size);
+ }
+ if (dname_size <= 0) {
+ idmap_scf_error(
+ gettext("Error obtaining the default domain"));
+ if (cfg->pgcfg.mapping_domain)
+ free(cfg->pgcfg.mapping_domain);
+ cfg->pgcfg.mapping_domain = NULL;
+ }
+ }
+
+ rc = get_val_astring(cfg, "machine_sid", &cfg->pgcfg.machine_sid);
+ if (rc != 0)
+ return (-1);
+
+ rc = get_val_astring(cfg, "global_catalog", &cfg->pgcfg.global_catalog);
+ if (rc != 0)
+ return (-1);
+
+ rc = get_val_astring(cfg, "domain_controller",
+ &cfg->pgcfg.domain_controller);
+ if (rc != 0)
+ return (-1);
+
+ return (rc);
+}
+
+idmap_cfg_t *
+idmap_cfg_init() {
+ /*
+ * The following initializes 'cfg'.
+ */
+
+ /* First the smf repository handles: */
+ idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
+ if (!cfg) {
+ idmap_error(gettext("Not enough memory"));
+ return (NULL);
+ }
+
+ if (!(cfg->handles.main = scf_handle_create(SCF_VERSION))) {
+ idmap_scf_error(gettext("SCF handle not created"));
+ goto error;
+ }
+
+ if (0 > scf_handle_bind(cfg->handles.main)) {
+ idmap_scf_error(gettext("SCF connection failed"));
+ goto error;
+ }
+
+ if (!(cfg->handles.service = scf_service_create(cfg->handles.main)) ||
+ !(cfg->handles.instance = scf_instance_create(cfg->handles.main)) ||
+ !(cfg->handles.config_pg = scf_pg_create(cfg->handles.main)) ||
+ !(cfg->handles.general_pg = scf_pg_create(cfg->handles.main))) {
+ idmap_scf_error(gettext("SCF handle creation failed"));
+ goto error;
+ }
+
+ if (0 > scf_handle_decode_fmri(cfg->handles.main,
+ FMRI_BASE "/:properties/" CONFIG_PG,
+ NULL, /* scope */
+ cfg->handles.service, /* service */
+ cfg->handles.instance, /* instance */
+ cfg->handles.config_pg, /* pg */
+ NULL, /* prop */
+ SCF_DECODE_FMRI_EXACT)) {
+ idmap_scf_error(gettext("SCF fmri decoding failed"));
+ goto error;
+
+ }
+
+ if (0 > scf_service_get_pg(cfg->handles.service,
+ GENERAL_PG, cfg->handles.general_pg)) {
+ idmap_scf_error(gettext("SCF general pg not obtained"));
+ goto error;
+ }
+
+ return (cfg);
+
+error:
+ (void) idmap_cfg_fini(cfg);
+ return (NULL);
+}
+
+/* ARGSUSED */
+static void
+idmap_pgcfg_fini(idmap_pg_config_t *pgcfg) {
+ if (pgcfg->mapping_domain)
+ free(pgcfg->mapping_domain);
+ if (pgcfg->machine_sid)
+ free(pgcfg->mapping_domain);
+ if (pgcfg->global_catalog)
+ free(pgcfg->global_catalog);
+ if (pgcfg->domain_controller)
+ free(pgcfg->domain_controller);
+}
+
+int
+idmap_cfg_fini(idmap_cfg_t *cfg)
+{
+ idmap_pgcfg_fini(&cfg->pgcfg);
+
+ scf_pg_destroy(cfg->handles.config_pg);
+ scf_pg_destroy(cfg->handles.general_pg);
+ scf_instance_destroy(cfg->handles.instance);
+ scf_service_destroy(cfg->handles.service);
+ scf_handle_destroy(cfg->handles.main);
+ free(cfg);
+
+ return (0);
+}
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.h b/usr/src/cmd/idmap/idmapd/idmap_config.h
new file mode 100644
index 0000000000..77bf513001
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.h
@@ -0,0 +1,72 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IDMAP_CONFIG_H
+#define _IDMAP_CONFIG_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "idmap.h"
+#include <libscf.h>
+#include <synch.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_POLICY_SIZE 1023
+
+typedef struct idmap_scf_handles {
+ scf_handle_t *main;
+ scf_instance_t *instance;
+ scf_service_t *service;
+ scf_propertygroup_t *config_pg;
+ scf_propertygroup_t *general_pg;
+} idmap_scf_handles_t;
+
+typedef struct idmap_pg_config {
+ uint64_t list_size_limit;
+ char *mapping_domain; /* mapping dopmain */
+ char *machine_sid; /* machine sid */
+ char *global_catalog; /* global catalog host */
+ char *domain_controller; /* domain controller host */
+ /* for mapping domain */
+} idmap_pg_config_t;
+
+typedef struct idmap_cfg {
+ idmap_pg_config_t pgcfg;
+ idmap_scf_handles_t handles;
+} idmap_cfg_t;
+
+extern idmap_cfg_t *idmap_cfg_init();
+extern int idmap_cfg_fini(idmap_cfg_t *);
+extern int idmap_cfg_load(idmap_cfg_t *);
+extern char *idmap_cfg_error();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IDMAP_CONFIG_H */
diff --git a/usr/src/cmd/idmap/idmapd/idmapd.c b/usr/src/cmd/idmap/idmapd/idmapd.c
new file mode 100644
index 0000000000..3f17c060e8
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/idmapd.c
@@ -0,0 +1,361 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * main() of idmapd(1M)
+ */
+
+#include "idmapd.h"
+#include <signal.h>
+#include <rpc/pmap_clnt.h> /* for pmap_unset */
+#include <string.h> /* strcmp */
+#include <unistd.h> /* setsid */
+#include <sys/types.h>
+#include <memory.h>
+#include <stropts.h>
+#include <netconfig.h>
+#include <sys/resource.h> /* rlimit */
+#include <syslog.h>
+#include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */
+#include <priv_utils.h> /* privileges */
+#include <locale.h>
+#include <sys/systeminfo.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <zone.h>
+#include <door.h>
+#include <tsol/label.h>
+#include <sys/resource.h>
+#include <sys/sid.h>
+#include <sys/idmap.h>
+
+static void hup_handler(int);
+static void term_handler(int);
+static void init_idmapd();
+static void fini_idmapd();
+
+#ifndef SIG_PF
+#define SIG_PF void(*)(int)
+#endif
+
+#define _RPCSVC_CLOSEDOWN 120
+
+int _rpcsvcstate = _IDLE; /* Set when a request is serviced */
+int _rpcsvccount = 0; /* Number of requests being serviced */
+mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */
+idmapd_state_t _idmapdstate;
+
+SVCXPRT *xprt = NULL;
+
+static int dfd = -1; /* our door server fildes, for unregistration */
+
+#ifdef DEBUG
+#define RPC_SVC_FG
+#endif
+
+/*
+ * This is needed for mech_krb5 -- we run as daemon, yes, but we want
+ * mech_krb5 to think we're root.
+ *
+ * Someday we'll have gss/mech_krb5 extensions for acquiring initiator
+ * creds with keytabs/raw keys, and someday we'll have extensions to
+ * libsasl to specify creds/name to use on the initiator side, and
+ * someday we'll have extensions to libldap to pass those through to
+ * libsasl. Until then this interposer will have to do.
+ *
+ * Also, we have to tell lint to shut up: it thinks app_krb5_user_uid()
+ * is defined but not used.
+ */
+/*LINTLIBRARY*/
+uid_t
+app_krb5_user_uid(void)
+{
+ return (0);
+}
+
+static void
+set_signal_handlers() {
+ (void) sigset(SIGPIPE, SIG_IGN);
+ (void) sigset(SIGHUP, hup_handler);
+ (void) sigset(SIGTERM, term_handler);
+}
+
+/*ARGSUSED*/
+static void
+hup_handler(int sig) {
+ (void) idmapdlog(LOG_INFO, "idmapd: Refreshing config.");
+ WRLOCK_CONFIG();
+ (void) idmap_cfg_fini(_idmapdstate.cfg);
+ _idmapdstate.cfg = NULL;
+ if (load_config() < 0) {
+ UNLOCK_CONFIG();
+ (void) idmapdlog(LOG_NOTICE,
+ "idmapd: Failed to reload config");
+ term_handler(sig);
+ }
+ UNLOCK_CONFIG();
+ print_idmapdstate();
+}
+
+/*ARGSUSED*/
+static void
+term_handler(int sig) {
+ (void) idmapdlog(LOG_INFO, "idmapd: Terminating.");
+ fini_idmapd();
+ _exit(0);
+}
+
+static int pipe_fd = -1;
+
+static void
+daemonize_ready(void) {
+ char data = '\0';
+ /*
+ * wake the parent
+ */
+ (void) write(pipe_fd, &data, 1);
+ (void) close(pipe_fd);
+}
+
+static int
+daemonize_start(void) {
+ char data;
+ int status;
+ int devnull;
+ int filedes[2];
+ pid_t pid;
+
+ devnull = open("/dev/null", O_RDONLY);
+ if (devnull < 0)
+ return (-1);
+ (void) dup2(devnull, 0);
+ (void) dup2(2, 1); /* stderr only */
+ if (pipe(filedes) < 0)
+ return (-1);
+ if ((pid = fork1()) < 0)
+ return (-1);
+ if (pid != 0) {
+ /*
+ * parent
+ */
+ struct sigaction act;
+ act.sa_sigaction = SIG_DFL;
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ (void) sigaction(SIGPIPE, &act, NULL); /* ignore SIGPIPE */
+ (void) close(filedes[1]);
+ if (read(filedes[0], &data, 1) == 1) {
+ /* presume success */
+ _exit(0);
+ }
+ status = -1;
+ (void) wait4(pid, &status, 0, NULL);
+ if (WIFEXITED(status))
+ _exit(WEXITSTATUS(status));
+ else
+ _exit(-1);
+ }
+
+ /*
+ * child
+ */
+ pipe_fd = filedes[1];
+ (void) close(filedes[0]);
+ (void) setsid();
+ (void) umask(0077);
+ openlog("idmap", LOG_PID, LOG_DAEMON);
+ _idmapdstate.daemon_mode = TRUE;
+ return (0);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int c;
+#ifdef RPC_SVC_FG
+ bool_t daemonize = FALSE;
+#else
+ bool_t daemonize = TRUE;
+#endif
+
+ while ((c = getopt(argc, argv, "d")) != EOF) {
+ switch (c) {
+ case 'd':
+ daemonize = FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* set locale and domain for internationalization */
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ if (is_system_labeled() && (getzoneid() != GLOBAL_ZONEID)) {
+ (void) idmapdlog(LOG_ERR,
+ "idmapd: With TX, idmapd runs only in the global zone");
+ exit(1);
+ }
+
+ /* create directories as root and chown to daemon uid */
+ if (create_directory(IDMAP_DBDIR, DAEMON_UID, DAEMON_GID) < 0)
+ exit(1);
+ if (create_directory(IDMAP_CACHEDIR, DAEMON_UID, DAEMON_GID) < 0)
+ exit(1);
+
+ INIT_IDMAPD_STATE();
+
+ (void) mutex_init(&_svcstate_lock, USYNC_THREAD, NULL);
+ set_signal_handlers();
+
+ if (daemonize == TRUE) {
+ if (daemonize_start() < 0) {
+ (void) perror("idmapd: unable to daemonize");
+ exit(-1);
+ }
+ } else
+ (void) umask(0077);
+
+ init_idmapd();
+
+ if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
+ DAEMON_UID, DAEMON_GID,
+ PRIV_PROC_AUDIT, PRIV_FILE_DAC_READ,
+ (char *)NULL) == -1) {
+ (void) idmapdlog(LOG_ERR,
+ gettext("idmapd: unable to drop privileges"));
+ exit(1);
+ }
+
+ __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
+ PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
+
+ if (daemonize == TRUE)
+ daemonize_ready();
+
+ /* With doors RPC this just wastes this thread, oh well */
+ svc_run();
+ return (0);
+}
+
+static void
+init_idmapd() {
+ int error;
+
+ memset(&_idmapdstate, 0, sizeof (_idmapdstate));
+
+ if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname,
+ sizeof (_idmapdstate.hostname)) == -1) {
+ error = errno;
+ idmapdlog(LOG_ERR,
+ "idmapd: unable to determine hostname, error: %d",
+ error);
+ exit(1);
+ }
+
+ if (sysinfo(SI_SRPC_DOMAIN, _idmapdstate.domainname,
+ sizeof (_idmapdstate.domainname)) == -1) {
+ error = errno;
+ idmapdlog(LOG_ERR,
+ "idmapd: unable to determine name service domain, error: %d",
+ error);
+ exit(1);
+ }
+
+ setegid(DAEMON_GID);
+ seteuid(DAEMON_UID);
+ if (init_mapping_system() < 0) {
+ idmapdlog(LOG_ERR,
+ "idmapd: unable to initialize mapping system");
+ exit(1);
+ }
+ seteuid(0);
+ setegid(0);
+
+ xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, 0);
+ if (xprt == NULL) {
+ idmapdlog(LOG_ERR,
+ "idmapd: unable to create door RPC service");
+ goto errout;
+ }
+
+ dfd = xprt->xp_fd;
+
+ if (dfd == -1) {
+ idmapdlog(LOG_ERR, "idmapd: unable to register door");
+ goto errout;
+ }
+ if ((error = idmap_reg(dfd)) != 0) {
+ idmapdlog(LOG_ERR, "idmapd: unable to register door (%s)",
+ strerror(error));
+ goto errout;
+ }
+
+ if ((error = allocids(_idmapdstate.new_eph_db,
+ 8192, &_idmapdstate.next_uid,
+ 8192, &_idmapdstate.next_gid)) != 0) {
+ idmapdlog(LOG_ERR, "idmapd: unable to allocate ephemeral IDs "
+ "(%s)", strerror(error));
+ _idmapdstate.next_uid = _idmapdstate.limit_uid = SENTINEL_PID;
+ _idmapdstate.next_gid = _idmapdstate.limit_gid = SENTINEL_PID;
+ } else {
+ _idmapdstate.limit_uid = _idmapdstate.next_uid + 8192;
+ _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192;
+ }
+
+ print_idmapdstate();
+
+ return;
+
+errout:
+ fini_idmapd();
+ exit(1);
+}
+
+static void
+fini_idmapd() {
+ idmap_unreg(dfd);
+ fini_mapping_system();
+ if (xprt != NULL)
+ svc_destroy(xprt);
+}
+
+void
+idmapdlog(int pri, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ if (_idmapdstate.daemon_mode == FALSE) {
+ (void) vfprintf(stderr, format, args);
+ (void) fprintf(stderr, "\n");
+ }
+ (void) vsyslog(pri, format, args);
+ va_end(args);
+}
diff --git a/usr/src/cmd/idmap/idmapd/idmapd.h b/usr/src/cmd/idmap/idmapd/idmapd.h
new file mode 100644
index 0000000000..79808445b3
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/idmapd.h
@@ -0,0 +1,185 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IDMAPD_H
+#define _IDMAPD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <rpc/rpc.h>
+#include <synch.h>
+#include <thread.h>
+#include <libintl.h>
+#include <strings.h>
+#include <sqlite/sqlite.h>
+#include <inttypes.h>
+#include "idmap_prot.h"
+#include "adutils.h"
+#include "idmap_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* States a server can be in wrt request */
+#define _IDLE 0
+#define _SERVED 1
+
+#define CHECK_NULL(s) s?s:"null"
+
+#define SENTINEL_PID UINT32_MAX
+
+extern int _rpcsvcstate; /* set when a request is serviced */
+extern int _rpcsvccount; /* number of requests being serviced */
+extern mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */
+
+/*
+ * Global state of idmapd daemon.
+ */
+#define IDMAP_MAX_NAME_LEN 512
+typedef struct idmapd_state {
+ rwlock_t rwlk_cfg; /* config lock */
+ idmap_cfg_t *cfg; /* config */
+ bool_t daemon_mode; /* daemon mode? yes/no */
+ char hostname[MAX_NAME_LEN]; /* my hostname */
+ char domainname[IDMAP_MAX_NAME_LEN]; /* my domain */
+ uid_t next_uid;
+ gid_t next_gid;
+ uid_t limit_uid;
+ gid_t limit_gid;
+ int new_eph_db; /* was the ephem ID db [re-]created? */
+ ad_t *ad;
+} idmapd_state_t;
+extern idmapd_state_t _idmapdstate;
+
+#define INIT_IDMAPD_STATE() \
+ (void) memset(&_idmapdstate, 0, sizeof (_idmapdstate));
+
+#define RDLOCK_CONFIG() \
+ (void) rw_rdlock(&_idmapdstate.rwlk_cfg);
+#define WRLOCK_CONFIG() \
+ (void) rw_wrlock(&_idmapdstate.rwlk_cfg);
+#define UNLOCK_CONFIG() \
+ (void) rw_unlock(&_idmapdstate.rwlk_cfg);
+
+typedef struct lookup_state {
+ bool_t sid2pid_done;
+ bool_t pid2sid_done;
+ idmap_query_state_t *ad_lookup;
+ int ad_nqueries;
+} lookup_state_t;
+
+typedef struct list_cb_data {
+ void *result;
+ uint64_t next;
+ uint64_t len;
+ uint64_t limit;
+} list_cb_data_t;
+
+typedef struct msg_table {
+ idmap_retcode retcode;
+ const char *msg;
+} msg_table_t;
+
+typedef struct wksids_table {
+ const char *sidprefix;
+ uint32_t rid;
+ int is_user;
+ uid_t pid;
+ int direction;
+} wksids_table_t;
+
+
+#define _IDMAP_F_DONE 0x00000000
+#define _IDMAP_F_S2N_CACHE 0x00000001
+#define _IDMAP_F_S2N_AD 0x00000002
+#define _IDMAP_F_EXP_EPH_UID 0x00000004
+#define _IDMAP_F_EXP_EPH_GID 0x00000010
+
+#define SIZE_INCR 5
+#define MAX_TRIES 5
+#define IDMAP_DBDIR "/var/idmap"
+#define IDMAP_CACHEDIR "/var/run/idmap"
+#define IDMAP_DBNAME IDMAP_DBDIR "/idmap.db"
+#define IDMAP_CACHENAME IDMAP_CACHEDIR "/idmap.db"
+
+typedef idmap_retcode (*update_list_res_cb)(void *, const char **, uint64_t);
+typedef int (*list_svc_cb)(void *, int, char **, char **);
+
+extern void idmap_prog_1(struct svc_req *, register SVCXPRT *);
+extern void idmapdlog(int, const char *, ...);
+extern int init_mapping_system();
+extern void fini_mapping_system();
+extern void print_idmapdstate();
+extern int create_directory(const char *, uid_t, gid_t);
+extern int load_config();
+
+
+extern int init_dbs();
+extern void fini_dbs();
+extern idmap_retcode get_db_handle(sqlite **);
+extern idmap_retcode get_cache_handle(sqlite **);
+extern idmap_retcode sql_exec_no_cb(sqlite *, char *);
+extern idmap_retcode add_namerule(sqlite *, idmap_namerule *);
+extern idmap_retcode rm_namerule(sqlite *, idmap_namerule *);
+extern idmap_retcode flush_namerules(sqlite *, bool_t);
+
+extern idmap_retcode gen_sql_expr_from_utf8str(const char *,
+ const char *, const char *,
+ idmap_utf8str *, const char *,
+ char **);
+extern idmap_retcode validate_list_cb_data(list_cb_data_t *, int,
+ char **, int, uchar_t **, size_t);
+extern idmap_retcode process_list_svc_sql(sqlite *, char *, uint64_t,
+ list_svc_cb, void *);
+extern idmap_retcode sid2pid_first_pass(lookup_state_t *, sqlite *,
+ idmap_mapping *, idmap_id_res *);
+extern idmap_retcode sid2pid_second_pass(lookup_state_t *, sqlite *,
+ sqlite *, idmap_mapping *, idmap_id_res *);
+extern idmap_retcode pid2sid_first_pass(lookup_state_t *, sqlite *,
+ sqlite *, idmap_mapping *, idmap_id_res *,
+ int, int);
+extern idmap_retcode update_cache_sid2pid(lookup_state_t *, sqlite *,
+ idmap_mapping *, idmap_id_res *);
+extern idmap_retcode update_cache_pid2sid(lookup_state_t *, sqlite *,
+ idmap_mapping *, idmap_id_res *);
+extern idmap_retcode get_u2w_mapping(sqlite *, sqlite *, idmap_mapping *,
+ idmap_mapping *, int);
+extern idmap_retcode get_w2u_mapping(sqlite *, sqlite *, idmap_mapping *,
+ idmap_mapping *);
+
+extern idmap_retcode lookup_win_batch_sid2name(lookup_state_t *,
+ idmap_mapping_batch *, idmap_ids_res *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IDMAPD_H */
diff --git a/usr/src/cmd/idmap/idmapd/init.c b/usr/src/cmd/idmap/idmapd/init.c
new file mode 100644
index 0000000000..f07256058c
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/init.c
@@ -0,0 +1,151 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Initialization routines
+ */
+
+#include "idmapd.h"
+#include <signal.h>
+#include <thread.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static const char *me = "idmapd";
+
+int
+init_mapping_system() {
+ if (rwlock_init(&_idmapdstate.rwlk_cfg, USYNC_THREAD, NULL) != 0)
+ return (-1);
+ if (load_config() < 0)
+ return (-1);
+ if (init_dbs() < 0) {
+ fini_mapping_system();
+ return (-1);
+ }
+ return (0);
+}
+
+void
+fini_mapping_system() {
+ fini_dbs();
+}
+
+int
+load_config() {
+ if ((_idmapdstate.cfg = idmap_cfg_init()) == NULL) {
+ idmapdlog(LOG_ERR, "%s: config init failed - %s",
+ me, CHECK_NULL(idmap_cfg_error()));
+ return (-1);
+ }
+ if (_idmapdstate.ad != NULL)
+ idmap_ad_free(&_idmapdstate.ad);
+ if (idmap_cfg_load(_idmapdstate.cfg) < 0) {
+ idmapdlog(LOG_ERR, "%s: config load failed - %s",
+ me, CHECK_NULL(idmap_cfg_error()));
+ return (-1);
+ }
+ if (_idmapdstate.cfg->pgcfg.mapping_domain == NULL ||
+ _idmapdstate.cfg->pgcfg.mapping_domain[0] == '\0') {
+ idmapdlog(LOG_ERR, "%s: Joined AD domain not configured; name "
+ "based and ephemeral mapping will not function", me);
+ } else if (idmap_ad_alloc(&_idmapdstate.ad,
+ _idmapdstate.cfg->pgcfg.mapping_domain,
+ IDMAP_AD_GLOBAL_CATALOG) != 0) {
+ idmapdlog(LOG_ERR, "%s: could not initialize AD context",
+ me);
+ return (-1);
+ }
+ if (_idmapdstate.cfg->pgcfg.global_catalog == NULL ||
+ _idmapdstate.cfg->pgcfg.global_catalog[0] == '\0') {
+ idmapdlog(LOG_ERR, "%s: Global catalog DSnot configured; name "
+ "based and ephemeral mapping will not function", me);
+ } else if (idmap_add_ds(_idmapdstate.ad,
+ _idmapdstate.cfg->pgcfg.global_catalog, 0) != 0) {
+ idmapdlog(LOG_ERR, "%s: could not initialize AD DS context",
+ me);
+ return (-1);
+ }
+ return (0);
+}
+
+void
+print_idmapdstate() {
+ RDLOCK_CONFIG();
+
+ if (_idmapdstate.daemon_mode == FALSE) {
+ (void) fprintf(stderr, "%s: daemon_mode=%s\n",
+ me, _idmapdstate.daemon_mode == TRUE?"true":"false");
+ (void) fprintf(stderr, "%s: hostname=%s\n",
+ me, _idmapdstate.hostname);
+ (void) fprintf(stderr, "%s; name service domain=%s\n", me,
+ _idmapdstate.domainname);
+
+ (void) fprintf(stderr, "%s: config=%s\n", me,
+ _idmapdstate.cfg?"not null":"null");
+ }
+ if (_idmapdstate.cfg == NULL || _idmapdstate.daemon_mode == TRUE)
+ goto out;
+ (void) fprintf(stderr, "%s: list_size_limit=%llu\n", me,
+ _idmapdstate.cfg->pgcfg.list_size_limit);
+ (void) fprintf(stderr, "%s: mapping_domain=%s\n", me,
+ CHECK_NULL(_idmapdstate.cfg->pgcfg.mapping_domain));
+ (void) fprintf(stderr, "%s: machine_sid=%s\n", me,
+ CHECK_NULL(_idmapdstate.cfg->pgcfg.machine_sid));
+ (void) fprintf(stderr, "%s: global_catalog=%s\n", me,
+ CHECK_NULL(_idmapdstate.cfg->pgcfg.global_catalog));
+ (void) fprintf(stderr, "%s: domain_controller=%s\n", me,
+ CHECK_NULL(_idmapdstate.cfg->pgcfg.domain_controller));
+out:
+ UNLOCK_CONFIG();
+}
+
+int
+create_directory(const char *path, uid_t uid, gid_t gid) {
+ int rc;
+
+ if ((rc = mkdir(path, 0700)) < 0 && errno != EEXIST) {
+ idmapdlog(LOG_ERR,
+ "%s: Error creating directory %s (%s)",
+ me, path, strerror(errno));
+ return (-1);
+ }
+
+ if (lchown(path, uid, gid) < 0) {
+ idmapdlog(LOG_ERR,
+ "%s: Error creating directory %s (%s)",
+ me, path, strerror(errno));
+ if (rc == 0)
+ (void) rmdir(path);
+ return (-1);
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/idmap/idmapd/mapfile-intf b/usr/src/cmd/idmap/idmapd/mapfile-intf
new file mode 100644
index 0000000000..1e34e55428
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/mapfile-intf
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+# idmapd exports app_krb5_user_uid() - required by mech_krb5.
+{
+ global:
+ app_krb5_user_uid;
+};
diff --git a/usr/src/cmd/idmap/idmapd/rpc_svc.c b/usr/src/cmd/idmap/idmapd/rpc_svc.c
new file mode 100644
index 0000000000..a59b9c8aa6
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/rpc_svc.c
@@ -0,0 +1,189 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * RPC service routines
+ * It was initially generated using rpcgen.
+ */
+
+#include "idmapd.h"
+#include "idmap_prot.h"
+#include <stdlib.h>
+#include <signal.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc.h>
+#include <string.h>
+#include <thread.h>
+#include <synch.h>
+
+
+/* ARGSUSED */
+int
+_idmap_null_1(void *argp, void *result, struct svc_req *rqstp)
+{
+ return (idmap_null_1_svc(result, rqstp));
+}
+
+int
+_idmap_get_mapped_ids_1(idmap_mapping_batch *argp, idmap_ids_res *result,
+ struct svc_req *rqstp) {
+ return (idmap_get_mapped_ids_1_svc(*argp, result, rqstp));
+}
+
+int
+_idmap_list_mappings_1(idmap_list_mappings_1_argument *argp,
+ idmap_mappings_res *result, struct svc_req *rqstp) {
+ return (idmap_list_mappings_1_svc(argp->is_user, argp->lastrowid,
+ argp->limit, result, rqstp));
+}
+
+int
+_idmap_list_namerules_1(idmap_list_namerules_1_argument *argp,
+ idmap_namerules_res *result, struct svc_req *rqstp) {
+ return (idmap_list_namerules_1_svc(argp->rule, argp->lastrowid,
+ argp->limit, result, rqstp));
+}
+
+int
+_idmap_update_1(idmap_update_batch *argp, idmap_retcode *result,
+ struct svc_req *rqstp) {
+ return (idmap_update_1_svc(*argp, result, rqstp));
+}
+
+int
+_idmap_get_mapped_id_by_name_1(idmap_mapping *argp,
+ idmap_mappings_res *result, struct svc_req *rqstp) {
+ return (idmap_get_mapped_id_by_name_1_svc(*argp, result, rqstp));
+}
+
+
+void
+idmap_prog_1(struct svc_req *rqstp, register SVCXPRT *transp)
+{
+ union {
+ idmap_mapping_batch idmap_get_mapped_ids_1_arg;
+ idmap_list_mappings_1_argument idmap_list_mappings_1_arg;
+ idmap_list_namerules_1_argument idmap_list_namerules_1_arg;
+ idmap_update_batch idmap_update_1_arg;
+ idmap_mapping idmap_get_mapped_id_by_name_1_arg;
+ } argument;
+ union {
+ idmap_ids_res idmap_get_mapped_ids_1_res;
+ idmap_mappings_res idmap_list_mappings_1_res;
+ idmap_namerules_res idmap_list_namerules_1_res;
+ idmap_retcode idmap_update_1_res;
+ idmap_mappings_res idmap_get_mapped_id_by_name_1_res;
+ } result;
+ bool_t retval;
+ xdrproc_t _xdr_argument, _xdr_result;
+ bool_t (*local)(char *, void *, struct svc_req *);
+
+ (void) mutex_lock(&_svcstate_lock);
+ _rpcsvccount++;
+ (void) mutex_unlock(&_svcstate_lock);
+ switch (rqstp->rq_proc) {
+ case IDMAP_NULL:
+ _xdr_argument = (xdrproc_t)xdr_void;
+ _xdr_result = (xdrproc_t)xdr_void;
+ local = (bool_t (*) (char *, void *, struct svc_req *))
+ _idmap_null_1;
+ break;
+
+ case IDMAP_GET_MAPPED_IDS:
+ _xdr_argument = (xdrproc_t)xdr_idmap_mapping_batch;
+ _xdr_result = (xdrproc_t)xdr_idmap_ids_res;
+ local = (bool_t (*) (char *, void *, struct svc_req *))
+ _idmap_get_mapped_ids_1;
+ break;
+
+ case IDMAP_LIST_MAPPINGS:
+ _xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
+ _xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
+ local = (bool_t (*) (char *, void *, struct svc_req *))
+ _idmap_list_mappings_1;
+ break;
+
+ case IDMAP_LIST_NAMERULES:
+ _xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
+ _xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
+ local = (bool_t (*) (char *, void *, struct svc_req *))
+ _idmap_list_namerules_1;
+ break;
+
+ case IDMAP_UPDATE:
+ _xdr_argument = (xdrproc_t)xdr_idmap_update_batch;
+ _xdr_result = (xdrproc_t)xdr_idmap_retcode;
+ local = (bool_t (*) (char *, void *, struct svc_req *))
+ _idmap_update_1;
+ break;
+
+ case IDMAP_GET_MAPPED_ID_BY_NAME:
+ _xdr_argument = (xdrproc_t)xdr_idmap_mapping;
+ _xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
+ local = (bool_t (*) (char *, void *, struct svc_req *))
+ _idmap_get_mapped_id_by_name_1;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ (void) mutex_lock(&_svcstate_lock);
+ _rpcsvccount--;
+ _rpcsvcstate = _SERVED;
+ (void) mutex_unlock(&_svcstate_lock);
+ return;
+ }
+ (void) memset((char *)&argument, 0, sizeof (argument));
+ if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) {
+ svcerr_decode(transp);
+ (void) mutex_lock(&_svcstate_lock);
+ _rpcsvccount--;
+ _rpcsvcstate = _SERVED;
+ (void) mutex_unlock(&_svcstate_lock);
+ return;
+ }
+ retval = (bool_t)(*local)((char *)&argument, (void *)&result, rqstp);
+ if (_xdr_result && retval > 0 && !svc_sendreply(transp, _xdr_result,
+ (char *)&result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, _xdr_argument, (caddr_t)&argument)) {
+ idmapdlog(LOG_ERR,
+ "unable to free RPC arguments");
+ exit(1);
+ }
+ if (_xdr_result != NULL) {
+ if (!idmap_prog_1_freeresult(transp, _xdr_result,
+ (caddr_t)&result))
+ idmapdlog(LOG_ERR,
+ "unable to free RPC results");
+
+ }
+ (void) mutex_lock(&_svcstate_lock);
+ _rpcsvccount--;
+ _rpcsvcstate = _SERVED;
+ (void) mutex_unlock(&_svcstate_lock);
+}
diff --git a/usr/src/cmd/idmap/idmapd/server.c b/usr/src/cmd/idmap/idmapd/server.c
new file mode 100644
index 0000000000..a79c6e2f5a
--- /dev/null
+++ b/usr/src/cmd/idmap/idmapd/server.c
@@ -0,0 +1,726 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Service routines
+ */
+
+#include "idmapd.h"
+#include "idmap_priv.h"
+#include <signal.h>
+#include <thread.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ucred.h>
+#include <pwd.h>
+#include <auth_attr.h>
+#include <secdb.h>
+
+#define _VALIDATE_LIST_CB_DATA(col, val, siz)\
+ retcode = validate_list_cb_data(cb_data, argc, argv, col,\
+ (uchar_t **)val, siz);\
+ if (retcode == IDMAP_NEXT) {\
+ result->retcode = IDMAP_NEXT;\
+ return (0);\
+ } else if (retcode < 0) {\
+ result->retcode = retcode;\
+ return (1);\
+ }
+
+#define PROCESS_LIST_SVC_SQL(rcode, db, sql, limit, cb, res, len)\
+ rcode = process_list_svc_sql(db, sql, limit, cb, res);\
+ if (rcode == IDMAP_ERR_BUSY)\
+ res->retcode = IDMAP_ERR_BUSY;\
+ else if (rcode == IDMAP_SUCCESS && len == 0)\
+ res->retcode = IDMAP_ERR_NOTFOUND;
+
+
+/* ARGSUSED */
+bool_t
+idmap_null_1_svc(void *result, struct svc_req *rqstp) {
+ return (TRUE);
+}
+
+#define IS_BATCH_SID(batch, i)\
+ batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_SID
+
+#define IS_BATCH_UID(batch, i)\
+ batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_UID
+
+#define IS_BATCH_GID(batch, i)\
+ batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_GID
+
+#define IS_REQUEST_SID(request)\
+ request.id1.idtype == IDMAP_SID
+
+#define IS_REQUEST_UID(request)\
+ request.id1.idtype == IDMAP_UID
+
+#define IS_REQUEST_GID(request)\
+ request.id1.idtype == IDMAP_GID
+
+/* ARGSUSED */
+bool_t
+idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch,
+ idmap_ids_res *result, struct svc_req *rqstp) {
+ sqlite *cache = NULL, *db = NULL;
+ lookup_state_t state;
+ idmap_retcode retcode, winrc;
+ int i;
+
+ /* Init */
+ (void) memset(result, 0, sizeof (*result));
+ (void) memset(&state, 0, sizeof (state));
+
+ /* Return success if nothing was requested */
+ if (batch.idmap_mapping_batch_len < 1)
+ goto out;
+
+ /* Get cache handle */
+ result->retcode = get_cache_handle(&cache);
+ if (result->retcode != IDMAP_SUCCESS)
+ goto out;
+
+ /* Get db handle */
+ result->retcode = get_db_handle(&db);
+ if (result->retcode != IDMAP_SUCCESS)
+ goto out;
+
+ /* Allocate result array */
+ result->ids.ids_val = calloc(batch.idmap_mapping_batch_len,
+ sizeof (idmap_id_res));
+ if (result->ids.ids_val == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ result->retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ result->ids.ids_len = batch.idmap_mapping_batch_len;
+
+ /* Init our 'done' flags */
+ state.sid2pid_done = state.pid2sid_done = TRUE;
+
+ /* First stage */
+ for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
+ if (IS_BATCH_SID(batch, i)) {
+ retcode = sid2pid_first_pass(
+ &state,
+ cache,
+ &batch.idmap_mapping_batch_val[i],
+ &result->ids.ids_val[i]);
+ } else if (IS_BATCH_UID(batch, i)) {
+ retcode = pid2sid_first_pass(
+ &state,
+ cache,
+ db,
+ &batch.idmap_mapping_batch_val[i],
+ &result->ids.ids_val[i], 1, 0);
+ } else if (IS_BATCH_GID(batch, i)) {
+ retcode = pid2sid_first_pass(
+ &state,
+ cache,
+ db,
+ &batch.idmap_mapping_batch_val[i],
+ &result->ids.ids_val[i], 0, 0);
+ } else {
+ result->ids.ids_val[i].retcode = IDMAP_ERR_IDTYPE;
+ continue;
+ }
+ if (IDMAP_FATAL_ERROR(retcode)) {
+ result->retcode = retcode;
+ goto out;
+ }
+ }
+
+ /* Check if we are done */
+ if (state.sid2pid_done == TRUE && state.pid2sid_done == TRUE)
+ goto out;
+
+ /* Process Windows server lookups for sid2name */
+ if (state.ad_nqueries) {
+ winrc = lookup_win_batch_sid2name(&state, &batch,
+ result);
+ if (IDMAP_FATAL_ERROR(winrc)) {
+ result->retcode = winrc;
+ goto out;
+ }
+ } else
+ winrc = IDMAP_SUCCESS;
+
+ /* Reset sid2pid 'done' flag */
+ state.sid2pid_done = TRUE;
+
+ /* Second stage */
+ for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
+ /* Process sid to pid ONLY */
+ if (IS_BATCH_SID(batch, i)) {
+ if (IDMAP_ERROR(winrc))
+ result->ids.ids_val[i].retcode = winrc;
+ retcode = sid2pid_second_pass(
+ &state,
+ cache,
+ db,
+ &batch.idmap_mapping_batch_val[i],
+ &result->ids.ids_val[i]);
+ if (IDMAP_FATAL_ERROR(retcode)) {
+ result->retcode = retcode;
+ goto out;
+ }
+ }
+ }
+
+ /* Check if we are done */
+ if (state.sid2pid_done == TRUE && state.pid2sid_done == TRUE)
+ goto out;
+
+ /* Reset our 'done' flags */
+ state.sid2pid_done = state.pid2sid_done = TRUE;
+
+ /* Update cache in a single transaction */
+ if (sql_exec_no_cb(cache, "BEGIN TRANSACTION;") != IDMAP_SUCCESS)
+ goto out;
+
+ for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
+ if (IS_BATCH_SID(batch, i)) {
+ (void) update_cache_sid2pid(
+ &state,
+ cache,
+ &batch.idmap_mapping_batch_val[i],
+ &result->ids.ids_val[i]);
+ } else if ((IS_BATCH_UID(batch, i)) ||
+ (IS_BATCH_GID(batch, i))) {
+ (void) update_cache_pid2sid(
+ &state,
+ cache,
+ &batch.idmap_mapping_batch_val[i],
+ &result->ids.ids_val[i]);
+ }
+ }
+
+ /* Commit if we have atleast one successful update */
+ if (state.sid2pid_done == FALSE || state.pid2sid_done == FALSE)
+ (void) sql_exec_no_cb(cache, "COMMIT TRANSACTION;");
+ else
+ (void) sql_exec_no_cb(cache, "END TRANSACTION;");
+
+out:
+ if (IDMAP_ERROR(result->retcode)) {
+ xdr_free(xdr_idmap_ids_res, (caddr_t)result);
+ result->ids.ids_len = 0;
+ result->ids.ids_val = NULL;
+ }
+ if (cache)
+ (void) sqlite_close(cache);
+ if (db)
+ (void) sqlite_close(db);
+ result->retcode = idmap_stat4prot(result->retcode);
+ return (TRUE);
+}
+
+
+/* ARGSUSED */
+static int
+list_mappings_cb(void *parg, int argc, char **argv, char **colnames) {
+ list_cb_data_t *cb_data;
+ char *str;
+ idmap_mappings_res *result;
+ idmap_utf8str *ptr;
+ idmap_retcode retcode;
+ int w2u, u2w;
+ char *end;
+
+ cb_data = (list_cb_data_t *)parg;
+ result = (idmap_mappings_res *)cb_data->result;
+
+ _VALIDATE_LIST_CB_DATA(9, &result->mappings.mappings_val,
+ sizeof (idmap_mapping));
+
+ result->mappings.mappings_len++;
+
+ if ((str = strdup(argv[1])) == NULL)
+ return (1);
+ result->mappings.mappings_val[cb_data->next].id1.idmap_id_u.sid.prefix =
+ str;
+ result->mappings.mappings_val[cb_data->next].id1.idmap_id_u.sid.rid =
+ strtoul(argv[2], &end, 10);
+ result->mappings.mappings_val[cb_data->next].id1.idtype = IDMAP_SID;
+
+ result->mappings.mappings_val[cb_data->next].id2.idmap_id_u.uid =
+ strtoul(argv[3], &end, 10);
+ result->mappings.mappings_val[cb_data->next].id2.idtype = IDMAP_UID;
+
+ w2u = argv[4]?strtol(argv[4], &end, 10):0;
+ u2w = argv[5]?strtol(argv[5], &end, 10):0;
+
+ if (w2u > 0 && u2w == 0)
+ result->mappings.mappings_val[cb_data->next].direction = 1;
+ else if (w2u == 0 && u2w > 0)
+ result->mappings.mappings_val[cb_data->next].direction = 2;
+ else
+ result->mappings.mappings_val[cb_data->next].direction = 0;
+
+ ptr = &result->mappings.mappings_val[cb_data->next].id1domain;
+ if (idmap_str2utf8(&ptr, argv[6], 0) != IDMAP_SUCCESS)
+ return (1);
+
+ ptr = &result->mappings.mappings_val[cb_data->next].id1name;
+ if (idmap_str2utf8(&ptr, argv[7], 0) != IDMAP_SUCCESS)
+ return (1);
+
+ ptr = &result->mappings.mappings_val[cb_data->next].id2name;
+ if (idmap_str2utf8(&ptr, argv[8], 0) != IDMAP_SUCCESS)
+ return (1);
+
+ result->lastrowid = strtoll(argv[0], &end, 10);
+ cb_data->next++;
+ result->retcode = IDMAP_SUCCESS;
+ return (0);
+}
+
+
+/* ARGSUSED */
+bool_t
+idmap_list_mappings_1_svc(bool_t is_user, int64_t lastrowid,
+ uint64_t limit, idmap_mappings_res *result,
+ struct svc_req *rqstp) {
+ sqlite *cache = NULL;
+ char lbuf[30], rbuf[30];
+ uint64_t maxlimit;
+ idmap_retcode retcode;
+ char *sql = NULL;
+
+ (void) memset(result, 0, sizeof (*result));
+ lbuf[0] = rbuf[0] = 0;
+
+ RDLOCK_CONFIG();
+ maxlimit = _idmapdstate.cfg->pgcfg.list_size_limit;
+ UNLOCK_CONFIG();
+
+ /* Get cache handle */
+ result->retcode = get_cache_handle(&cache);
+ if (result->retcode != IDMAP_SUCCESS)
+ goto out;
+
+ result->retcode = IDMAP_ERR_INTERNAL;
+
+ /* Create LIMIT expression. */
+ if (limit == 0 || (maxlimit > 0 && maxlimit < limit))
+ limit = maxlimit;
+ if (limit > 0)
+ (void) snprintf(lbuf, sizeof (lbuf),
+ "LIMIT %" PRIu64, limit + 1ULL);
+
+ (void) snprintf(rbuf, sizeof (rbuf), "rowid > %" PRIu64, lastrowid);
+
+ /*
+ * Combine all the above into a giant SELECT statement that
+ * will return the requested mappings
+ */
+ sql = sqlite_mprintf("SELECT rowid, sidprefix, rid, pid, w2u, u2w,"
+ " windomain, winname, unixname"
+ " FROM idmap_cache WHERE "
+ " %s AND is_user = %d %s;",
+ rbuf, is_user?1:0, lbuf);
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ /* Execute the SQL statement and update the return buffer */
+ PROCESS_LIST_SVC_SQL(retcode, cache, sql, limit, list_mappings_cb,
+ result, result->mappings.mappings_len);
+
+out:
+ if (sql)
+ sqlite_freemem(sql);
+ if (IDMAP_ERROR(result->retcode))
+ (void) xdr_free(xdr_idmap_mappings_res, (caddr_t)result);
+ if (cache)
+ (void) sqlite_close(cache);
+ result->retcode = idmap_stat4prot(result->retcode);
+ return (TRUE);
+}
+
+
+/* ARGSUSED */
+static int
+list_namerules_cb(void *parg, int argc, char **argv, char **colnames) {
+ list_cb_data_t *cb_data;
+ idmap_namerules_res *result;
+ idmap_retcode retcode;
+ idmap_utf8str *ptr;
+ int w2u_order, u2w_order;
+ char *end;
+
+ cb_data = (list_cb_data_t *)parg;
+ result = (idmap_namerules_res *)cb_data->result;
+
+ _VALIDATE_LIST_CB_DATA(8, &result->rules.rules_val,
+ sizeof (idmap_namerule));
+
+ result->rules.rules_len++;
+
+ result->rules.rules_val[cb_data->next].is_user =
+ strtol(argv[1], &end, 10);
+
+ ptr = &result->rules.rules_val[cb_data->next].windomain;
+ if (idmap_str2utf8(&ptr, argv[2], 0) != IDMAP_SUCCESS)
+ return (1);
+
+ ptr = &result->rules.rules_val[cb_data->next].winname;
+ if (idmap_str2utf8(&ptr, argv[3], 0) != IDMAP_SUCCESS)
+ return (1);
+
+ result->rules.rules_val[cb_data->next].is_nt4 =
+ strtol(argv[4], &end, 10);
+
+ ptr = &result->rules.rules_val[cb_data->next].unixname;
+ if (idmap_str2utf8(&ptr, argv[5], 0) != IDMAP_SUCCESS)
+ return (1);
+
+ w2u_order = argv[6]?strtol(argv[6], &end, 10):0;
+ u2w_order = argv[7]?strtol(argv[7], &end, 10):0;
+
+ if (w2u_order > 0 && u2w_order == 0)
+ result->rules.rules_val[cb_data->next].direction = 1;
+ else if (w2u_order == 0 && u2w_order > 0)
+ result->rules.rules_val[cb_data->next].direction = 2;
+ else
+ result->rules.rules_val[cb_data->next].direction = 0;
+
+ result->lastrowid = strtoll(argv[0], &end, 10);
+ cb_data->next++;
+ result->retcode = IDMAP_SUCCESS;
+ return (0);
+}
+
+
+/* ARGSUSED */
+bool_t
+idmap_list_namerules_1_svc(idmap_namerule rule, uint64_t lastrowid,
+ uint64_t limit, idmap_namerules_res *result,
+ struct svc_req *rqstp) {
+
+ sqlite *db = NULL;
+ char w2ubuf[15], u2wbuf[15];
+ char lbuf[30], rbuf[30];
+ char *sql = NULL;
+ char *s_windomain = NULL, *s_winname = NULL;
+ char *s_unixname = NULL;
+ uint64_t maxlimit;
+ idmap_retcode retcode;
+
+ (void) memset(result, 0, sizeof (*result));
+ lbuf[0] = rbuf[0] = 0;
+
+ RDLOCK_CONFIG();
+ maxlimit = _idmapdstate.cfg->pgcfg.list_size_limit;
+ UNLOCK_CONFIG();
+
+ /* Get db handle */
+ result->retcode = get_db_handle(&db);
+ if (result->retcode != IDMAP_SUCCESS)
+ goto out;
+
+ result->retcode = IDMAP_ERR_INTERNAL;
+
+ if (rule.direction < 0) {
+ w2ubuf[0] = u2wbuf[0] = 0;
+ } else if (rule.direction == 0) {
+ (void) snprintf(w2ubuf, sizeof (w2ubuf), "AND w2u_order > 0");
+ (void) snprintf(u2wbuf, sizeof (u2wbuf), "AND u2w_order > 0");
+ } else if (rule.direction == 1) {
+ (void) snprintf(w2ubuf, sizeof (w2ubuf), "AND w2u_order > 0");
+ (void) snprintf(u2wbuf, sizeof (u2wbuf),
+ "AND (u2w_order = 0 OR u2w_order ISNULL)");
+ } else if (rule.direction == 2) {
+ (void) snprintf(w2ubuf, sizeof (w2ubuf),
+ "AND (w2u_order = 0 OR w2u_order ISNULL)");
+ (void) snprintf(u2wbuf, sizeof (u2wbuf), "AND u2w_order > 0");
+ }
+
+ /* Create where statement for windomain */
+ if (rule.windomain.idmap_utf8str_len > 0) {
+ if (gen_sql_expr_from_utf8str("AND", "windomain", "=",
+ &rule.windomain,
+ "", &s_windomain) != IDMAP_SUCCESS)
+ goto out;
+ }
+
+ /* Create where statement for winname */
+ if (rule.winname.idmap_utf8str_len > 0) {
+ if (gen_sql_expr_from_utf8str("AND", "winname", "=",
+ &rule.winname,
+ "", &s_winname) != IDMAP_SUCCESS)
+ goto out;
+ }
+
+ /* Create where statement for unixname */
+ if (rule.unixname.idmap_utf8str_len > 0) {
+ if (gen_sql_expr_from_utf8str("AND", "unixname", "=",
+ &rule.unixname,
+ "", &s_unixname) != IDMAP_SUCCESS)
+ goto out;
+ }
+
+ /* Create LIMIT expression. */
+ if (limit == 0 || (maxlimit > 0 && maxlimit < limit))
+ limit = maxlimit;
+ if (limit > 0)
+ (void) snprintf(lbuf, sizeof (lbuf),
+ "LIMIT %" PRIu64, limit + 1ULL);
+
+ (void) snprintf(rbuf, sizeof (rbuf), "rowid > %" PRIu64, lastrowid);
+
+ /*
+ * Combine all the above into a giant SELECT statement that
+ * will return the requested rules
+ */
+ sql = sqlite_mprintf("SELECT rowid, is_user, windomain, winname, "
+ "is_nt4, unixname, w2u_order, u2w_order "
+ "FROM namerules WHERE "
+ " %s AND is_user = %d %s %s %s %s %s %s;",
+ rbuf, rule.is_user?1:0,
+ s_windomain?s_windomain:"",
+ s_winname?s_winname:"",
+ s_unixname?s_unixname:"",
+ w2ubuf, u2wbuf, lbuf);
+ if (sql == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ goto out;
+ }
+
+ /* Execute the SQL statement and update the return buffer */
+ PROCESS_LIST_SVC_SQL(retcode, db, sql, limit, list_namerules_cb,
+ result, result->rules.rules_len);
+
+out:
+ if (s_windomain)
+ sqlite_freemem(s_windomain);
+ if (s_winname)
+ sqlite_freemem(s_winname);
+ if (s_unixname)
+ sqlite_freemem(s_unixname);
+ if (sql)
+ sqlite_freemem(sql);
+ if (IDMAP_ERROR(result->retcode))
+ (void) xdr_free(xdr_idmap_namerules_res, (caddr_t)result);
+ if (db)
+ (void) sqlite_close(db);
+ result->retcode = idmap_stat4prot(result->retcode);
+ return (TRUE);
+}
+
+#define IDMAP_RULES_AUTH "solaris.admin.idmap.rules"
+static int
+verify_rules_auth(struct svc_req *rqstp) {
+ ucred_t *uc = NULL;
+ uid_t uid;
+ char buf[1024];
+ struct passwd pwd;
+ const char *me = "verify_rules_auth";
+
+ if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
+ idmapdlog(LOG_ERR,
+ "%s: svc_getcallerucred failed (errno=%d)",
+ me, errno);
+ return (-1);
+ }
+
+ uid = ucred_geteuid(uc);
+ if (uid == (uid_t)-1) {
+ idmapdlog(LOG_ERR,
+ "%s: ucred_geteuid failed (errno=%d)",
+ me, errno);
+ ucred_free(uc);
+ return (-1);
+ }
+
+ if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL) {
+ idmapdlog(LOG_ERR,
+ "%s: getpwuid_r(%u) failed (errno=%d)",
+ me, uid, errno);
+ ucred_free(uc);
+ return (-1);
+ }
+
+ if (chkauthattr(IDMAP_RULES_AUTH, pwd.pw_name) != 1) {
+ idmapdlog(LOG_INFO,
+ "%s: %s does not have authorization.",
+ me, pwd.pw_name);
+ ucred_free(uc);
+ return (-1);
+ }
+
+ ucred_free(uc);
+ return (1);
+}
+
+/* ARGSUSED */
+bool_t
+idmap_update_1_svc(idmap_update_batch batch, idmap_retcode *result,
+ struct svc_req *rqstp) {
+ sqlite *db = NULL;
+ idmap_update_op *up;
+ int i;
+
+ if (verify_rules_auth(rqstp) < 0) {
+ *result = IDMAP_ERR_PERMISSION_DENIED;
+ goto out;
+ }
+
+ if (batch.idmap_update_batch_len == 0 ||
+ batch.idmap_update_batch_val == NULL) {
+ *result = IDMAP_SUCCESS;
+ goto out;
+ }
+
+ /* Get db handle */
+ *result = get_db_handle(&db);
+ if (*result != IDMAP_SUCCESS)
+ goto out;
+
+ *result = sql_exec_no_cb(db, "BEGIN TRANSACTION;");
+ if (*result != IDMAP_SUCCESS)
+ goto out;
+
+ for (i = 0; i < batch.idmap_update_batch_len; i++) {
+ up = &batch.idmap_update_batch_val[i];
+ switch (up->opnum) {
+ case OP_NONE:
+ *result = IDMAP_SUCCESS;
+ break;
+ case OP_ADD_NAMERULE:
+ *result = add_namerule(db,
+ &up->idmap_update_op_u.rule);
+ break;
+ case OP_RM_NAMERULE:
+ *result = rm_namerule(db,
+ &up->idmap_update_op_u.rule);
+ break;
+ case OP_FLUSH_NAMERULES:
+ *result = flush_namerules(db,
+ up->idmap_update_op_u.is_user);
+ break;
+ default:
+ *result = IDMAP_ERR_NOTSUPPORTED;
+ goto out;
+ };
+
+ if (*result != IDMAP_SUCCESS)
+ goto out;
+ }
+
+out:
+ if (*result == IDMAP_SUCCESS && db) {
+ *result = sql_exec_no_cb(db, "COMMIT TRANSACTION;");
+ }
+
+ if (db)
+ (void) sqlite_close(db);
+ *result = idmap_stat4prot(*result);
+ return (TRUE);
+}
+
+
+/* ARGSUSED */
+bool_t
+idmap_get_mapped_id_by_name_1_svc(idmap_mapping request,
+ idmap_mappings_res *result, struct svc_req *rqstp) {
+ sqlite *cache = NULL, *db = NULL;
+
+ /* Init */
+ (void) memset(result, 0, sizeof (*result));
+
+ /* Get cache handle */
+ result->retcode = get_cache_handle(&cache);
+ if (result->retcode != IDMAP_SUCCESS)
+ goto out;
+
+ /* Get db handle */
+ result->retcode = get_db_handle(&db);
+ if (result->retcode != IDMAP_SUCCESS)
+ goto out;
+
+ /* Allocate result */
+ result->mappings.mappings_val = calloc(1, sizeof (idmap_mapping));
+ if (result->mappings.mappings_val == NULL) {
+ idmapdlog(LOG_ERR, "Out of memory");
+ result->retcode = IDMAP_ERR_MEMORY;
+ goto out;
+ }
+ result->mappings.mappings_len = 1;
+
+ if (IS_REQUEST_SID(request)) {
+ result->retcode = get_w2u_mapping(
+ cache,
+ db,
+ &request,
+ result->mappings.mappings_val);
+ } else if (IS_REQUEST_UID(request)) {
+ result->retcode = get_u2w_mapping(
+ cache,
+ db,
+ &request,
+ result->mappings.mappings_val,
+ 1);
+ } else if (IS_REQUEST_GID(request)) {
+ result->retcode = get_u2w_mapping(
+ cache,
+ db,
+ &request,
+ result->mappings.mappings_val,
+ 0);
+ } else {
+ result->retcode = IDMAP_ERR_IDTYPE;
+ }
+
+out:
+ if (IDMAP_FATAL_ERROR(result->retcode)) {
+ xdr_free(xdr_idmap_mappings_res, (caddr_t)result);
+ result->mappings.mappings_len = 0;
+ result->mappings.mappings_val = NULL;
+ }
+ if (cache)
+ (void) sqlite_close(cache);
+ if (db)
+ (void) sqlite_close(db);
+ result->retcode = idmap_stat4prot(result->retcode);
+ return (TRUE);
+}
+
+
+/* ARGSUSED */
+int
+idmap_prog_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result,
+ caddr_t result) {
+ (void) xdr_free(xdr_result, result);
+ return (TRUE);
+}
diff --git a/usr/src/cmd/idmap/req.flg b/usr/src/cmd/idmap/req.flg
new file mode 100644
index 0000000000..1b5d312e4f
--- /dev/null
+++ b/usr/src/cmd/idmap/req.flg
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+echo_file usr/src/head/Makefile
+echo_file usr/src/head/rpcsvc/idmap_prot.x
+echo_file usr/src/lib/libidmap/Makefile
diff --git a/usr/src/cmd/rpcsvc/net_files/rpc b/usr/src/cmd/rpcsvc/net_files/rpc
index 4fd1179b5a..ba6756af03 100644
--- a/usr/src/cmd/rpcsvc/net_files/rpc
+++ b/usr/src/cmd/rpcsvc/net_files/rpc
@@ -1,13 +1,12 @@
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -22,7 +21,7 @@
#
# CDDL HEADER END
#
-# ident "%Z%%M% %I% %E% SMI" /* Svr4.0 1.2 */
+# ident "%Z%%M% %I% %E% SMI"
#
# rpc
#
@@ -92,3 +91,4 @@ metad 100229 metad
metamhd 100230 metamhd
metamedd 100242 metamedd
smserverd 100155 smserverd
+idmap 100172 idmap
diff --git a/usr/src/cmd/sqlite/Makefile b/usr/src/cmd/sqlite/Makefile
new file mode 100644
index 0000000000..5cc113b608
--- /dev/null
+++ b/usr/src/cmd/sqlite/Makefile
@@ -0,0 +1,69 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG= sqlite
+
+include ../Makefile.cmd
+
+include $(SRC)/lib/Makefile.lib
+
+SQLITEHDRDIR= $(ROOTHDRDIR)/sqlite
+LIBSQLITE= $(ROOTLIBDIR)/libsqlite.o
+
+ROOTLIBSVCBIN= $(ROOT)/lib/svc/bin
+ROOTSQLITE= $(PROG:%=$(ROOTLIBSVCBIN)/%)
+
+OBJS= shell.o
+$(OBJS) := CFLAGS += $(CTF_FLAGS)
+$(OBJS) := CTFCONVERT_POST = $(CTFCONVERT_O)
+
+.KEEP_STATE:
+
+$(ROOTSQLITE) := FILEMODE= 555
+
+$(ROOTLIBSVCBIN)/%: %
+ $(INS.file)
+
+CPPFLAGS += -D_REENTRANT -DTHREADSAFE=1 -DHAVE_USLEEP=1 \
+ -I$(SQLITEHDRDIR)
+
+$(PROG): $(OBJS) $(SQLITEHDRDIR)/sqlite.h
+ $(LINK.c) -o $@ $(OBJS) \
+ $(MAPFILE.NES:%=-M%) $(MAPFILE.NED:%=-M%) $(LIBSQLITE)
+ $(CTFMERGE) -t -L VERSION -o $@ $(OBJS) $(LIBSQLITE)
+ $(POST_PROCESS)
+
+all: $(PROG)
+
+install: all $(ROOTSQLITE)
+
+clean:
+ $(RM) $(OBJS)
+
+lint:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/svc/configd/sqlite/src/shell.c b/usr/src/cmd/sqlite/shell.c
index fe1291e08c..fe1291e08c 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/shell.c
+++ b/usr/src/cmd/sqlite/shell.c
diff --git a/usr/src/cmd/svc/configd/Makefile b/usr/src/cmd/svc/configd/Makefile
index a2fd9b5efb..910651f997 100644
--- a/usr/src/cmd/svc/configd/Makefile
+++ b/usr/src/cmd/svc/configd/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -50,7 +50,7 @@ $(NATIVE_BUILD)OBJS = $(MYOBJS:%.o=%-native.o)
ROOTCMDDIR= $(ROOT)/lib/svc/bin
-MYCPPFLAGS = -I. -I../common -I../../../common/svc -D_REENTRANT
+MYCPPFLAGS = -I. -I../common -I../../../common/svc -I$(ROOT)/usr/include/sqlite -D_REENTRANT
CPPFLAGS += $(MYCPPFLAGS)
CFLAGS += -v
MYLDLIBS = -lumem -luutil
@@ -79,10 +79,9 @@ FILEMODE = 0555
OWNER = root
GROUP = sys
-SQLITEDIR = sqlite
-LIBSQLITE = $(SQLITEDIR)/libsqlite.o
-$(NATIVE_BUILD)LIBSQLITE = $(SQLITEDIR)/libsqlite-native.o
-SQLITELINT = $(SQLITEDIR)/llib-lsqlite.ln
+LIBSQLITE = $(ROOT)/usr/lib/libsqlite.o
+$(NATIVE_BUILD)LIBSQLITE = $(ROOT)/usr/lib/libsqlite-native.o
+SQLITELINT = $(ROOT)/usr/lib/llib-lsqlite.ln
OBJS += $(LIBSQLITE)
@@ -100,19 +99,7 @@ native: FRC
@cd $(LIBUUTIL)/native; pwd; $(MAKE) $(MFLAGS) install
@NATIVE_BUILD= $(MAKE) $(MFLAGS) all
-$(SQLITEDIR): FRC
- @cd $(SQLITEDIR); pwd; $(MAKE) $(TARGET)
-
-$(SQLITEDIR)/libsqlite.o: FRC
- @cd $(SQLITEDIR); pwd; $(MAKE) all
-
-$(SQLITEDIR)/libsqlite-native.o: FRC
- @cd $(SQLITEDIR); pwd; $(MAKE) native
-
-$(SQLITEDIR)/llib-lsqlite.ln: FRC
- @cd $(SQLITEDIR); pwd; $(MAKE) llib-lsqlite.ln
-
-$(PROG): $(LIBSQLITE) $(OBJS)
+$(PROG): $(OBJS)
$(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK)
$(POST_PROCESS)
@@ -123,16 +110,16 @@ $(PROG): $(LIBSQLITE) $(OBJS)
$(ROOTCMDDIR)/%: %.sh
$(INS.rename)
-install: all $(SQLITEDIR) $(ROOTCMD) $(ROOTVARSADMFILE) $(ROOTSCRIPTFILE)
+install: all $(ROOTCMD) $(ROOTVARSADMFILE) $(ROOTSCRIPTFILE)
clean: FRC
$(RM) $(MYOBJS) $(MYOBJS:%.o=%-native.o)
-clobber: $(SQLITEDIR)
+clobber:
lint: lint_SRCS
-lint_SRCS: $(SQLITELINT)
+lint_SRCS:
include ../../Makefile.targ
diff --git a/usr/src/cmd/svc/configd/backend.c b/usr/src/cmd/svc/configd/backend.c
index ad7fd95579..62fc26ebc0 100644
--- a/usr/src/cmd/svc/configd/backend.c
+++ b/usr/src/cmd/svc/configd/backend.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -53,8 +52,8 @@
#include "configd.h"
#include "repcache_protocol.h"
-#include "sqlite/sqlite.h"
-#include "sqlite/sqlite-misc.h"
+#include <sqlite.h>
+#include <sqlite-misc.h>
/*
* This file has two purposes:
@@ -1297,9 +1296,9 @@ integrity_fail:
" can be run to restore a backup version of your repository. See\n"
" http://sun.com/msg/SMF-8000-MY for more information.\n"
"\n",
- db_file,
- (fname == NULL)? ":\n\n" : " is in:\n\n ",
- (fname == NULL)? integrity_results : fname);
+ db_file,
+ (fname == NULL)? ":\n\n" : " is in:\n\n ",
+ (fname == NULL)? integrity_results : fname);
}
free(errp);
goto fail;
diff --git a/usr/src/head/rpcsvc/idmap_prot.x b/usr/src/head/rpcsvc/idmap_prot.x
new file mode 100644
index 0000000000..f9cfcebf55
--- /dev/null
+++ b/usr/src/head/rpcsvc/idmap_prot.x
@@ -0,0 +1,160 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+%#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* opaque type to support non-ASCII strings */
+typedef opaque idmap_utf8str<>;
+
+/* Return status */
+typedef int idmap_retcode;
+
+/* Identity types */
+enum idmap_id_type {
+ IDMAP_NONE = 0,
+ IDMAP_UID = 1,
+ IDMAP_GID,
+ IDMAP_SID,
+ IDMAP_POSIXID
+};
+
+/* SID */
+struct idmap_sid {
+ string prefix<>;
+ uint32_t rid;
+};
+
+/* Identity (sid-posix) */
+union idmap_id switch(idmap_id_type idtype) {
+ case IDMAP_UID: uint32_t uid;
+ case IDMAP_GID: uint32_t gid;
+ case IDMAP_SID: idmap_sid sid;
+ case IDMAP_NONE: void;
+ case IDMAP_POSIXID: void;
+};
+struct idmap_id_res {
+ idmap_retcode retcode;
+ idmap_id id;
+ int direction;
+};
+struct idmap_ids_res {
+ idmap_retcode retcode;
+ idmap_id_res ids<>;
+};
+
+
+/*
+ * Flag supported by mapping requests
+ */
+/* Don't allocate a new value for the mapping */
+const IDMAP_REQ_FLG_NO_NEW_ID_ALLOC = 0x00000001;
+/* Validate the given identity before mapping */
+const IDMAP_REQ_FLG_VALIDATE = 0x00000002;
+/* Avoid name service lookups to prevent looping */
+const IDMAP_REQ_FLG_NO_NAMESERVICE = 0x00000004;
+
+/* Identity mappings (sid-posix) */
+struct idmap_mapping {
+ int32_t flag;
+ int direction;
+ idmap_id id1;
+ idmap_utf8str id1domain;
+ idmap_utf8str id1name;
+ idmap_id id2;
+ idmap_utf8str id2domain;
+ idmap_utf8str id2name;
+};
+struct idmap_mappings_res {
+ idmap_retcode retcode;
+ uint64_t lastrowid;
+ idmap_mapping mappings<>;
+};
+typedef idmap_mapping idmap_mapping_batch<>;
+
+
+/* Name-based mapping rules */
+struct idmap_namerule {
+ bool is_user;
+ int direction;
+ idmap_utf8str windomain;
+ idmap_utf8str winname;
+ idmap_utf8str unixname;
+ bool is_nt4;
+};
+struct idmap_namerules_res {
+ idmap_retcode retcode;
+ uint64_t lastrowid;
+ idmap_namerule rules<>;
+};
+
+
+/* Update requests */
+enum idmap_opnum {
+ OP_NONE = 0,
+ OP_ADD_NAMERULE = 1,
+ OP_RM_NAMERULE = 2,
+ OP_FLUSH_NAMERULES = 3
+};
+union idmap_update_op switch(idmap_opnum opnum) {
+ case OP_ADD_NAMERULE:
+ case OP_RM_NAMERULE:
+ idmap_namerule rule;
+ case OP_FLUSH_NAMERULES:
+ bool is_user;
+ default:
+ void;
+};
+typedef idmap_update_op idmap_update_batch<>;
+
+
+program IDMAP_PROG {
+ version IDMAP_V1 {
+ void
+ IDMAP_NULL(void) = 0;
+
+ /* Batch of requests to get mapped identities */
+ idmap_ids_res
+ IDMAP_GET_MAPPED_IDS(idmap_mapping_batch batch) = 1;
+
+ /* List all identity mappings */
+ idmap_mappings_res
+ IDMAP_LIST_MAPPINGS(bool is_user, int64_t lastrowid,
+ uint64_t limit) = 2;
+
+ /* List all name-based mapping rules */
+ idmap_namerules_res
+ IDMAP_LIST_NAMERULES(idmap_namerule rule,
+ uint64_t lastrowid, uint64_t limit) = 3;
+
+ /* Batch of update requests */
+ idmap_retcode
+ IDMAP_UPDATE(idmap_update_batch batch) = 4;
+
+ /* Get mapped identity by name */
+ idmap_mappings_res
+ IDMAP_GET_MAPPED_ID_BY_NAME(idmap_mapping request) = 5;
+
+ } = 1;
+} = 100172;
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 16f1ac6a7b..3d0bcc05dd 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -226,6 +226,8 @@ SUBDIRS += \
policykit \
hal \
libshare \
+ libsqlite \
+ libidmap \
libipmi \
libexacct/demo \
$($(MACH)_SUBDIRS)
@@ -277,6 +279,7 @@ MSGSUBDIRS= \
libdiskmgt \
libdladm \
libgss \
+ libidmap \
libinetcfg \
libipmp \
libnsl \
@@ -373,6 +376,7 @@ HDRSUBDIRS= \
libsec \
libslp \
libsmedia \
+ libsqlite \
libsysevent \
libtecla \
libtnf \
@@ -400,6 +404,7 @@ HDRSUBDIRS= \
libmapid \
libkrb5 \
libshare \
+ libidmap \
$($(MACH)_HDRSUBDIRS)
$(CLOSED_BUILD)HDRSUBDIRS += \
@@ -479,6 +484,7 @@ libefi: libuuid
libfstyp: libnvpair
$(CLOSED_BUILD)$(CLOSED)/lib/libelfsign: \
$(CLOSED)/lib/libike libcryptoutil pkcs11
+libidmap: libnsl
libinetcfg: libnsl libsocket libdevinfo
libkmf: libcryptoutil pkcs11 openssl
libnsl: libmd5 libscf
diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc
index ae99d31f84..e5f386e3b2 100644
--- a/usr/src/lib/libc/port/llib-lc
+++ b/usr/src/lib/libc/port/llib-lc
@@ -112,6 +112,7 @@
#include <sys/rctl_impl.h>
#include <sys/sem.h>
#include <sys/shm.h>
+#include <sys/sid.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
diff --git a/usr/src/lib/libidmap/Makefile b/usr/src/lib/libidmap/Makefile
new file mode 100644
index 0000000000..87f8d55bbf
--- /dev/null
+++ b/usr/src/lib/libidmap/Makefile
@@ -0,0 +1,65 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.lib
+
+HDRS = idmap.h
+HDRDIR = common
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+POFILE = libidmap.po
+MSGFILES = `$(GREP) -l gettext common/*.[ch]`
+XGETFLAGS = -a
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(POFILE): pofile_MSGFILES
+ $(BUILDPO.msgfiles)
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libidmap/Makefile.com b/usr/src/lib/libidmap/Makefile.com
new file mode 100644
index 0000000000..825793fbc2
--- /dev/null
+++ b/usr/src/lib/libidmap/Makefile.com
@@ -0,0 +1,64 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libidmap.a
+VERS = .1
+OBJECTS = idmap_xdr.o utils.o idmap_api.o
+LINT_OBJECTS = utils.o idmap_api.o
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -lnsl
+
+SRCDIR = ../common
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+IDMAP_PROT_DIR = $(SRC)/head/rpcsvc
+IDMAP_PROT_X = $(IDMAP_PROT_DIR)/idmap_prot.x
+IDMAP_PROT_H = $(IDMAP_PROT_DIR)/idmap_prot.h
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I$(SRCDIR) -I$(IDMAP_PROT_DIR)
+#CPPFLAGS += -D_REENTRANT -I$(SRCDIR)
+CLOBBERFILES += $(IDMAP_PROT_H) $(SRCDIR)/idmap_xdr.c
+
+lint := OBJECTS = $(LINT_OBJECTS)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+$(IDMAP_PROT_H): $(IDMAP_PROT_X)
+ $(RM) $@; $(RPCGEN) -CMNh -o $@ $(IDMAP_PROT_X)
+
+$(SRCDIR)/idmap_xdr.c: $(IDMAP_PROT_H) $(IDMAP_PROT_X)
+ $(RM) $@; $(RPCGEN) -CMNc -o $@ $(IDMAP_PROT_X)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libidmap/amd64/Makefile b/usr/src/lib/libidmap/amd64/Makefile
new file mode 100644
index 0000000000..7c17fe3827
--- /dev/null
+++ b/usr/src/lib/libidmap/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libidmap/common/idmap.h b/usr/src/lib/libidmap/common/idmap.h
new file mode 100644
index 0000000000..d9d58cd794
--- /dev/null
+++ b/usr/src/lib/libidmap/common/idmap.h
@@ -0,0 +1,110 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Header File for Clients of Native Identity Mapping Service
+ */
+
+#ifndef _IDMAP_H
+#define _IDMAP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/idmap.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Status */
+typedef int32_t idmap_stat;
+
+typedef uint32_t idmap_rid_t;
+
+/* Opaque client handle */
+typedef struct idmap_handle idmap_handle_t;
+
+/* Opaque "get-mapping" handle */
+typedef struct idmap_get_handle idmap_get_handle_t;
+
+
+/*
+ * Setup API
+ */
+/* Create/Init handle for userland clients */
+extern idmap_stat idmap_init(idmap_handle_t **);
+
+/* Finalize/close handle */
+extern idmap_stat idmap_fini(idmap_handle_t *);
+
+/* Status code to string */
+extern const char *idmap_stat2string(idmap_handle_t *, idmap_stat);
+
+/* Free memory allocated by the API */
+extern void idmap_free(void *);
+
+
+/*
+ * API to batch SID to UID/GID mapping requests
+ */
+/* Create handle */
+extern idmap_stat idmap_get_create(idmap_handle_t *, idmap_get_handle_t **);
+
+/* Given SID, get UID */
+extern idmap_stat idmap_get_uidbysid(idmap_get_handle_t *, char *,
+ idmap_rid_t, int, uid_t *, idmap_stat *);
+
+/* Given SID, get GID */
+extern idmap_stat idmap_get_gidbysid(idmap_get_handle_t *, char *,
+ idmap_rid_t, int, gid_t *, idmap_stat *);
+
+/* Given SID, get UID or GID */
+extern idmap_stat idmap_get_pidbysid(idmap_get_handle_t *, char *,
+ idmap_rid_t, int, uid_t *, int *, idmap_stat *);
+
+/* Given UID, get SID */
+extern idmap_stat idmap_get_sidbyuid(idmap_get_handle_t *, uid_t, int,
+ char **, idmap_rid_t *, idmap_stat *);
+
+/* Given GID, get SID */
+extern idmap_stat idmap_get_sidbygid(idmap_get_handle_t *, gid_t, int,
+ char **, idmap_rid_t *, idmap_stat *);
+
+/* Process the batched requests */
+extern idmap_stat idmap_get_mappings(idmap_get_handle_t *);
+
+/* Destroy the handle */
+extern void idmap_get_destroy(idmap_get_handle_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IDMAP_H */
diff --git a/usr/src/lib/libidmap/common/idmap_api.c b/usr/src/lib/libidmap/common/idmap_api.c
new file mode 100644
index 0000000000..c47508e1d7
--- /dev/null
+++ b/usr/src/lib/libidmap/common/idmap_api.c
@@ -0,0 +1,1689 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * libidmap API
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <strings.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <libintl.h>
+#include "idmap_impl.h"
+
+static struct timeval TIMEOUT = { 25, 0 };
+
+static int idmap_stat2errno(idmap_stat);
+
+int __idmap_verbose;
+
+#define __ITER_CREATE(itera, argu, handl, ityp)\
+ if (handl == NULL) {\
+ errno = EINVAL;\
+ return (IDMAP_ERR_ARG);\
+ }\
+ itera = calloc(1, sizeof (*itera));\
+ if (itera == NULL) {\
+ if (__idmap_verbose)\
+ (void) fprintf(stderr, gettext("Out of memory\n"));\
+ errno = ENOMEM;\
+ return (IDMAP_ERR_MEMORY);\
+ }\
+ argu = calloc(1, sizeof (*argu));\
+ if (argu == NULL) {\
+ free(itera);\
+ if (__idmap_verbose)\
+ (void) fprintf(stderr, gettext("Out of memory\n"));\
+ errno = ENOMEM;\
+ return (IDMAP_ERR_MEMORY);\
+ }\
+ itera->ih = handl;\
+ itera->type = ityp;\
+ itera->retcode = IDMAP_NEXT;\
+ itera->limit = 1024;\
+ itera->arg = argu;
+
+
+#define __ITER_ERR_RETURN(itera, argu, xdr_argu, iretcod)\
+ if (argu) {\
+ xdr_free(xdr_argu, (caddr_t)argu);\
+ free(argu);\
+ }\
+ if (itera)\
+ free(itera);\
+ return (iretcod);
+
+
+#define __ITER_CHECK(itera, ityp)\
+ if (itera == NULL) {\
+ if (__idmap_verbose)\
+ (void) fprintf(stderr,\
+ gettext("%s: Iterator is null\n"), me);\
+ errno = EINVAL;\
+ return (IDMAP_ERR_ARG);\
+ }\
+ if (itera->type != ityp) {\
+ if (__idmap_verbose)\
+ (void) fprintf(stderr,\
+ gettext("%s: Invalid iterator\n"), me);\
+ errno = EINVAL;\
+ return (IDMAP_ERR_ARG);\
+ }
+
+
+/*
+ * Free memory allocated by libidmap API
+ *
+ * Input:
+ * ptr - memory to be freed
+ */
+void
+idmap_free(void *ptr) {
+ free(ptr);
+}
+
+
+/*
+ * Verbose on/off switch (Private)
+ *
+ * Input:
+ * on - TRUE=on, FALSE=off
+ */
+void
+idmap_set_verbose(boolean_t on) {
+ __idmap_verbose = (on == B_TRUE)?1:0;
+}
+
+
+/*
+ * Create and Initialize idmap client handle for rpc/doors
+ *
+ * Output:
+ * handle - idmap handle
+ */
+idmap_stat
+idmap_init(idmap_handle_t **handle) {
+ CLIENT *clnt = NULL;
+ struct idmap_handle *hptr;
+
+ *handle = NULL;
+ hptr = (struct idmap_handle *)calloc(1, sizeof (*hptr));
+ if (hptr == NULL)
+ return (IDMAP_ERR_MEMORY);
+
+ clnt = clnt_door_create(IDMAP_PROG, IDMAP_V1, 0);
+ if (clnt == NULL) {
+ if (__idmap_verbose)
+ clnt_pcreateerror("clnt_door_create");
+ free(hptr);
+ return (IDMAP_ERR_RPC);
+ }
+ hptr->type = _IDMAP_HANDLE_RPC_DOORS;
+ hptr->privhandle = clnt;
+ *handle = hptr;
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Finalize idmap handle
+ *
+ * Input:
+ * handle - idmap handle
+ */
+idmap_stat
+idmap_fini(idmap_handle_t *handle) {
+ CLIENT *clnt;
+ struct idmap_handle *hptr;
+
+ if (handle == NULL)
+ return (IDMAP_SUCCESS);
+
+ hptr = (struct idmap_handle *)handle;
+
+ switch (hptr->type) {
+ case _IDMAP_HANDLE_RPC_DOORS:
+ clnt = (CLIENT *)hptr->privhandle;
+ if (clnt) {
+ if (clnt->cl_auth)
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+ break;
+ default:
+ break;
+ }
+ free(hptr);
+ return (IDMAP_SUCCESS);
+}
+
+
+
+/*
+ * Create/Initialize handle for updates
+ *
+ * Output:
+ * udthandle - update handle
+ */
+idmap_stat
+idmap_udt_create(idmap_handle_t *handle, idmap_udt_handle_t **udthandle) {
+ idmap_udt_handle_t *tmp;
+ const char *me = "idmap_udt_create";
+
+ if (handle == NULL || udthandle == NULL) {
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+ if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("%s: Out of memory\n"), me);
+ errno = ENOMEM;
+ return (IDMAP_ERR_MEMORY);
+ }
+
+ tmp->ih = handle;
+ *udthandle = tmp;
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * All the updates specified by the update handle are committed
+ * in a single transaction. i.e either all succeed or none.
+ *
+ * Input:
+ * udthandle - update handle with the update requests
+ *
+ * Return value:
+ * Status of the commit
+ */
+idmap_stat
+idmap_udt_commit(idmap_udt_handle_t *udthandle) {
+ CLIENT *clnt;
+ enum clnt_stat clntstat;
+ idmap_retcode retcode;
+ const char *me = "idmap_udt_commit";
+
+ if (udthandle == NULL) {
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("%s: Invalid handle\n"), me);
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+ _IDMAP_GET_CLIENT_HANDLE(udthandle->ih, clnt);
+ clntstat = clnt_call(clnt, IDMAP_UPDATE,
+ (xdrproc_t)xdr_idmap_update_batch, (caddr_t)&udthandle->batch,
+ (xdrproc_t)xdr_idmap_retcode, (caddr_t)&retcode,
+ TIMEOUT);
+ if (clntstat != RPC_SUCCESS) {
+ if (__idmap_verbose)
+ clnt_perror(clnt, "IDMAP_UPDATE");
+ return (IDMAP_ERR_RPC);
+ }
+ if (retcode != IDMAP_SUCCESS)
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Destroy the update handle
+ */
+void
+idmap_udt_destroy(idmap_udt_handle_t *udthandle) {
+ if (udthandle == NULL)
+ return;
+ (void) xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
+ free(udthandle);
+}
+
+
+idmap_stat
+idmap_udt_add_namerule(idmap_udt_handle_t *udthandle, const char *windomain,
+ boolean_t is_user, const char *winname, const char *unixname,
+ boolean_t is_nt4, int direction) {
+ idmap_retcode retcode;
+ idmap_namerule *rule;
+ idmap_utf8str *str;
+
+ retcode = _udt_extend_batch(udthandle, OP_ADD_NAMERULE);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+
+ rule = &udthandle->batch.
+ idmap_update_batch_val[udthandle->next].
+ idmap_update_op_u.rule;
+ rule->is_user = is_user;
+ rule->direction = direction;
+ rule->is_nt4 = is_nt4;
+ if (windomain) {
+ str = &rule->windomain;
+ retcode = idmap_str2utf8(&str, windomain, 0);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (winname) {
+ str = &rule->winname;
+ retcode = idmap_str2utf8(&str, winname, 0);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (unixname) {
+ str = &rule->unixname;
+ retcode = idmap_str2utf8(&str, unixname, 0);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ udthandle->next++;
+ return (IDMAP_SUCCESS);
+
+errout:
+ (void) xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/* ARGSUSED */
+idmap_stat
+idmap_udt_rm_namerule(idmap_udt_handle_t *udthandle, boolean_t is_user,
+ const char *windomain, const char *winname,
+ const char *unixname, int direction) {
+ idmap_retcode retcode;
+ idmap_namerule *rule;
+ idmap_utf8str *str;
+
+ retcode = _udt_extend_batch(udthandle, OP_RM_NAMERULE);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+
+ rule = &udthandle->batch.
+ idmap_update_batch_val[udthandle->next].
+ idmap_update_op_u.rule;
+ rule->is_user = is_user;
+ rule->direction = direction;
+ if (windomain) {
+ str = &rule->windomain;
+ retcode = idmap_str2utf8(&str, windomain, 0);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (winname) {
+ str = &rule->winname;
+ retcode = idmap_str2utf8(&str, winname, 0);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (unixname) {
+ str = &rule->unixname;
+ retcode = idmap_str2utf8(&str, unixname, 0);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ udthandle->next++;
+ return (IDMAP_SUCCESS);
+
+errout:
+ (void) xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/* ARGSUSED */
+idmap_stat
+idmap_udt_flush_namerules(idmap_udt_handle_t *udthandle, boolean_t is_user) {
+ idmap_retcode retcode;
+
+ retcode = _udt_extend_batch(udthandle, OP_FLUSH_NAMERULES);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+
+ udthandle->batch.idmap_update_batch_val[udthandle->next].
+ idmap_update_op_u.is_user = is_user;
+
+ udthandle->next++;
+ return (IDMAP_SUCCESS);
+
+errout:
+ (void) xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Set the number of entries requested per batch by the iterator
+ *
+ * Input:
+ * iter - iterator
+ * limit - number of entries requested per batch
+ */
+idmap_stat
+idmap_iter_set_limit(idmap_iter_t *iter, uint64_t limit) {
+ if (iter == NULL) {
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+ iter->limit = limit;
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Create iterator to get name-based mapping rules
+ *
+ * Input:
+ * windomain - Windows domain
+ * is_user - user or group rules
+ * winname - Windows user or group name
+ * unixname - Unix user or group name
+ *
+ * Output:
+ * iter - iterator
+ */
+idmap_stat
+idmap_iter_namerules(idmap_handle_t *handle, const char *windomain,
+ boolean_t is_user, const char *winname,
+ const char *unixname, idmap_iter_t **iter) {
+
+ idmap_iter_t *tmpiter;
+ idmap_list_namerules_1_argument *arg = NULL;
+ idmap_namerule *rule;
+ idmap_utf8str *str;
+ idmap_retcode retcode;
+
+ __ITER_CREATE(tmpiter, arg, handle, IDMAP_LIST_NAMERULES);
+
+ rule = &arg->rule;
+ rule->is_user = is_user;
+ rule->direction = -1;
+ if (windomain) {
+ str = &rule->windomain;
+ retcode = idmap_str2utf8(&str, windomain, 0);
+ if (retcode != IDMAP_SUCCESS) {
+ errno = ENOMEM;
+ goto errout;
+ }
+ }
+ if (winname) {
+ str = &rule->winname;
+ retcode = idmap_str2utf8(&str, winname, 0);
+ if (retcode != IDMAP_SUCCESS) {
+ errno = ENOMEM;
+ goto errout;
+ }
+ }
+ if (unixname) {
+ str = &rule->unixname;
+ retcode = idmap_str2utf8(&str, unixname, 0);
+ if (retcode != IDMAP_SUCCESS) {
+ errno = ENOMEM;
+ goto errout;
+ }
+ }
+
+ *iter = tmpiter;
+ return (IDMAP_SUCCESS);
+
+errout:
+ __ITER_ERR_RETURN(tmpiter, arg,
+ xdr_idmap_list_namerules_1_argument, retcode);
+}
+
+
+/*
+ * Iterate through the name-based mapping rules
+ *
+ * Input:
+ * iter - iterator
+ *
+ * Output:
+ * windomain - Windows domain
+ * winname - Windows user or group name
+ * unixname - Unix user or group name
+ * is_nt4 - NT4 or AD
+ * direction - bi(0), win2unix(1), unix2win(2)
+ *
+ * Return value:
+ * 0 - done
+ * 1 - more results available
+ * < 0 - error
+ */
+idmap_stat
+idmap_iter_next_namerule(idmap_iter_t *iter, char **windomain,
+ char **winname, char **unixname, boolean_t *is_nt4,
+ int *direction) {
+ idmap_namerules_res *namerules;
+ idmap_list_namerules_1_argument *arg;
+ idmap_retcode retcode;
+ const char *me = "idmap_iter_next_namerule";
+
+ if (windomain)
+ *windomain = NULL;
+ if (winname)
+ *winname = NULL;
+ if (unixname)
+ *unixname = NULL;
+ if (is_nt4)
+ *is_nt4 = 0;
+ if (direction)
+ *direction = -1;
+
+ __ITER_CHECK(iter, IDMAP_LIST_NAMERULES);
+
+ namerules = (idmap_namerules_res *)iter->retlist;
+ if (iter->retcode == IDMAP_NEXT && (namerules == NULL ||
+ iter->next >= namerules->rules.rules_len)) {
+
+ if ((arg = iter->arg) == NULL) {
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+ arg->limit = iter->limit;
+
+ retcode = _iter_get_next_list(IDMAP_LIST_NAMERULES,
+ iter, arg,
+ (uchar_t **)&namerules, sizeof (*namerules),
+ (xdrproc_t)xdr_idmap_list_namerules_1_argument,
+ (xdrproc_t)xdr_idmap_namerules_res);
+ if (retcode != IDMAP_SUCCESS)
+ return (retcode);
+
+ if (IDMAP_ERROR(namerules->retcode)) {
+ retcode = namerules->retcode;
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("Server returned failure\n"));
+ xdr_free(xdr_idmap_namerules_res, (caddr_t)namerules);
+ free(namerules);
+ iter->retlist = NULL;
+ return (retcode);
+ }
+ iter->retcode = namerules->retcode;
+ arg->lastrowid = namerules->lastrowid;
+ }
+
+ if (namerules == NULL || namerules->rules.rules_len == 0)
+ return (IDMAP_SUCCESS);
+
+ if (iter->next >= namerules->rules.rules_len) {
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("%s: Invalid result\n"), me);
+ return (IDMAP_ERR_ARG);
+ }
+
+ if (windomain) {
+ retcode = idmap_utf82str(windomain, 0,
+ &namerules->rules.rules_val[iter->next].windomain);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (winname) {
+ retcode = idmap_utf82str(winname, 0,
+ &namerules->rules.rules_val[iter->next].winname);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (unixname) {
+ retcode = idmap_utf82str(unixname, 0,
+ &namerules->rules.rules_val[iter->next].unixname);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (is_nt4)
+ *is_nt4 = namerules->rules.rules_val[iter->next].is_nt4;
+ if (direction)
+ *direction = namerules->rules.rules_val[iter->next].direction;
+ iter->next++;
+
+ if (iter->next == namerules->rules.rules_len)
+ return (iter->retcode);
+ else
+ return (IDMAP_NEXT);
+
+errout:
+ if (windomain && *windomain)
+ free(*windomain);
+ if (winname && *winname)
+ free(*winname);
+ if (unixname && *unixname)
+ free(*unixname);
+ return (retcode);
+}
+
+
+/*
+ * Create iterator to get SID to UID/GID mappings
+ *
+ * Input:
+ * is_user - user or group
+ *
+ * Output:
+ * iter - iterator
+ */
+idmap_stat
+idmap_iter_mappings(idmap_handle_t *handle, boolean_t is_user,
+ idmap_iter_t **iter) {
+ idmap_iter_t *tmpiter;
+ idmap_list_mappings_1_argument *arg = NULL;
+
+ __ITER_CREATE(tmpiter, arg, handle, IDMAP_LIST_MAPPINGS);
+
+ arg->is_user = is_user;
+ *iter = tmpiter;
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Iterate through the SID to UID/GID mappings
+ *
+ * Input:
+ * iter - iterator
+ *
+ * Output:
+ * sid - SID in canonical form
+ * pid - UID or GID
+ *
+ * Return value:
+ * 0 - done
+ * 1 - more results available
+ * < 0 - error
+ */
+idmap_stat
+idmap_iter_next_mapping(idmap_iter_t *iter, char **sidprefix,
+ idmap_rid_t *rid, uid_t *pid, char **winname,
+ char **windomain, char **unixname, int *direction) {
+ idmap_mappings_res *mappings;
+ idmap_list_mappings_1_argument *arg;
+ idmap_retcode retcode;
+ char *str;
+ const char *me = "idmap_iter_next_mapping";
+
+ if (sidprefix)
+ *sidprefix = NULL;
+ if (rid)
+ *rid = UINT32_MAX;
+ if (winname)
+ *winname = NULL;
+ if (windomain)
+ *windomain = NULL;
+ if (unixname)
+ *unixname = NULL;
+ if (pid)
+ *pid = UINT32_MAX;
+ if (direction)
+ *direction = -1;
+
+ __ITER_CHECK(iter, IDMAP_LIST_MAPPINGS);
+
+ mappings = (idmap_mappings_res *)iter->retlist;
+ if (iter->retcode == IDMAP_NEXT && (mappings == NULL ||
+ iter->next >= mappings->mappings.mappings_len)) {
+
+ if ((arg = iter->arg) == NULL) {
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+ arg->limit = iter->limit;
+
+ retcode = _iter_get_next_list(IDMAP_LIST_MAPPINGS,
+ iter, arg,
+ (uchar_t **)&mappings, sizeof (*mappings),
+ (xdrproc_t)xdr_idmap_list_mappings_1_argument,
+ (xdrproc_t)xdr_idmap_mappings_res);
+ if (retcode != IDMAP_SUCCESS)
+ return (retcode);
+
+ if (IDMAP_ERROR(mappings->retcode)) {
+ retcode = mappings->retcode;
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("Server returned failure\n"));
+ xdr_free(xdr_idmap_mappings_res, (caddr_t)mappings);
+ free(mappings);
+ iter->retlist = NULL;
+ return (retcode);
+ }
+ iter->retcode = mappings->retcode;
+ arg->lastrowid = mappings->lastrowid;
+ }
+
+ if (mappings == NULL || mappings->mappings.mappings_len == 0)
+ return (IDMAP_SUCCESS);
+
+ if (iter->next >= mappings->mappings.mappings_len) {
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("%s: Invalid result\n"), me);
+ return (IDMAP_ERR_ARG);
+ }
+
+ if (sidprefix) {
+ str = mappings->mappings.mappings_val[iter->next].id1.
+ idmap_id_u.sid.prefix;
+ if (str)
+ *sidprefix = strdup(str);
+ else
+ *sidprefix = strdup("<sidprefix missing>");
+ if (*sidprefix == NULL) {
+ retcode = IDMAP_ERR_MEMORY;
+ goto errout;
+ }
+ }
+ if (rid)
+ *rid = mappings->mappings.mappings_val[iter->next].id1.
+ idmap_id_u.sid.rid;
+ if (winname) {
+ retcode = idmap_utf82str(winname, 0,
+ &mappings->mappings.mappings_val[iter->next].id1name);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (windomain) {
+ retcode = idmap_utf82str(windomain, 0,
+ &mappings->mappings.mappings_val[iter->next].id1domain);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (unixname) {
+ retcode = idmap_utf82str(unixname, 0,
+ &mappings->mappings.mappings_val[iter->next].id2name);
+ if (retcode != IDMAP_SUCCESS)
+ goto errout;
+ }
+ if (pid)
+ *pid = mappings->mappings.mappings_val[iter->next].id2.
+ idmap_id_u.uid;
+ if (direction)
+ *direction = mappings->mappings.mappings_val[iter->next].
+ direction;
+ iter->next++;
+
+ if (iter->next == mappings->mappings.mappings_len)
+ return (iter->retcode);
+ else
+ return (IDMAP_NEXT);
+
+errout:
+ if (sidprefix && *sidprefix)
+ free(*sidprefix);
+ if (winname && *winname)
+ free(*winname);
+ if (windomain && *windomain)
+ free(*windomain);
+ if (unixname && *unixname)
+ free(*unixname);
+ return (retcode);
+}
+
+
+/*
+ * Destroy the iterator
+ */
+void
+idmap_iter_destroy(idmap_iter_t *iter) {
+ xdrproc_t _xdr_argument, _xdr_result;
+
+ if (iter == NULL)
+ return;
+
+ switch (iter->type) {
+ case IDMAP_LIST_NAMERULES:
+ _xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
+ _xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
+ break;
+ case IDMAP_LIST_MAPPINGS:
+ _xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
+ _xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
+ break;
+ default:
+ free(iter);
+ return;
+ };
+
+ if (iter->arg) {
+ xdr_free(_xdr_argument, (caddr_t)iter->arg);
+ free(iter->arg);
+ }
+ if (iter->retlist) {
+ xdr_free(_xdr_result, (caddr_t)iter->retlist);
+ free(iter->retlist);
+ }
+ free(iter);
+}
+
+
+/*
+ * Create handle to get SID to UID/GID mapping entries
+ *
+ * Input:
+ * gh - "get mapping" handle
+ */
+idmap_stat
+idmap_get_create(idmap_handle_t *handle, idmap_get_handle_t **gh) {
+ idmap_get_handle_t *tmp;
+ const char *me = "idmap_get_create";
+
+ /* sanity checks */
+ if (handle == NULL || gh == NULL) {
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+
+ /* allocate the handle */
+ if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("%s: Out of memory\n"), me);
+ errno = ENOMEM;
+ return (IDMAP_ERR_MEMORY);
+ }
+
+ tmp->ih = handle;
+ *gh = tmp;
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Given SID, get UID
+ *
+ * Input:
+ * sidprefix - SID prefix
+ * rid - RID
+ * flag - flag
+ *
+ * Output:
+ * stat - status of the get request
+ * uid - POSIX UID if stat = 0
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+idmap_get_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
+ int flag, uid_t *uid, idmap_stat *stat) {
+
+ idmap_retcode retcode;
+ idmap_mapping *mapping;
+
+ /* sanity checks */
+ if (gh == NULL)
+ return (IDMAP_ERR_ARG);
+ if (uid == NULL || sidprefix == NULL)
+ return (IDMAP_ERR_ARG);
+
+ /* Extend the request array and the return list */
+ if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
+ goto errout;
+
+ /* Setup the request */
+ mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
+ mapping->flag = flag;
+ mapping->id1.idtype = IDMAP_SID;
+ mapping->id1.idmap_id_u.sid.rid = rid;
+ if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
+ retcode = IDMAP_ERR_MEMORY;
+ goto errout;
+ }
+ mapping->id2.idtype = IDMAP_UID;
+
+ /* Setup pointers for the result */
+ gh->retlist[gh->next].idtype = IDMAP_UID;
+ gh->retlist[gh->next].uid = uid;
+ gh->retlist[gh->next].stat = stat;
+
+ gh->next++;
+ return (IDMAP_SUCCESS);
+
+errout:
+ (void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
+ free(gh->retlist);
+ gh->retlist = NULL;
+ gh->next = 0;
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Given SID, get GID
+ *
+ * Input:
+ * sidprefix - SID prefix
+ * rid - rid
+ * flag - flag
+ *
+ * Output:
+ * stat - status of the get request
+ * gid - POSIX GID if stat = 0
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+idmap_get_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
+ int flag, gid_t *gid, idmap_stat *stat) {
+
+ idmap_retcode retcode;
+ idmap_mapping *mapping;
+
+ /* sanity checks */
+ if (gh == NULL)
+ return (IDMAP_ERR_ARG);
+ if (gid == NULL || sidprefix == NULL)
+ return (IDMAP_ERR_ARG);
+
+ /* Extend the request array and the return list */
+ if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
+ goto errout;
+
+ /* Setup the request */
+ mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
+ mapping->flag = flag;
+ mapping->id1.idtype = IDMAP_SID;
+ mapping->id1.idmap_id_u.sid.rid = rid;
+ if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
+ retcode = IDMAP_ERR_MEMORY;
+ goto errout;
+ }
+ mapping->id2.idtype = IDMAP_GID;
+
+ /* Setup pointers for the result */
+ gh->retlist[gh->next].idtype = IDMAP_GID;
+ gh->retlist[gh->next].gid = gid;
+ gh->retlist[gh->next].stat = stat;
+
+ gh->next++;
+ return (IDMAP_SUCCESS);
+
+errout:
+ (void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
+ free(gh->retlist);
+ gh->retlist = NULL;
+ gh->next = 0;
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Given SID, get POSIX ID i.e. UID/GID
+ *
+ * Input:
+ * sidprefix - SID prefix
+ * rid - rid
+ * flag - flag
+ *
+ * Output:
+ * stat - status of the get request
+ * is_user - user or group
+ * pid - POSIX UID if stat = 0 and is_user = 1
+ * POSIX GID if stat = 0 and is_user = 0
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+idmap_get_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
+ int flag, uid_t *pid, int *is_user, idmap_stat *stat) {
+ idmap_retcode retcode;
+ idmap_mapping *mapping;
+
+ /* sanity checks */
+ if (gh == NULL)
+ return (IDMAP_ERR_ARG);
+ if (pid == NULL || sidprefix == NULL || is_user == NULL)
+ return (IDMAP_ERR_ARG);
+
+ /* Extend the request array and the return list */
+ if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
+ goto errout;
+
+ /* Setup the request */
+ mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
+ mapping->flag = flag;
+ mapping->id1.idtype = IDMAP_SID;
+ mapping->id1.idmap_id_u.sid.rid = rid;
+ if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
+ retcode = IDMAP_ERR_MEMORY;
+ goto errout;
+ }
+ mapping->id2.idtype = IDMAP_POSIXID;
+
+ /* Setup pointers for the result */
+ gh->retlist[gh->next].idtype = IDMAP_POSIXID;
+ gh->retlist[gh->next].uid = pid;
+ gh->retlist[gh->next].gid = pid;
+ gh->retlist[gh->next].is_user = is_user;
+ gh->retlist[gh->next].stat = stat;
+
+ gh->next++;
+ return (IDMAP_SUCCESS);
+
+errout:
+ (void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
+ free(gh->retlist);
+ gh->retlist = NULL;
+ gh->next = 0;
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Given UID, get SID
+ *
+ * Input:
+ * uid - POSIX UID
+ * flag - flag
+ *
+ * Output:
+ * stat - status of the get request
+ * sid - SID prefix (if stat == 0)
+ * rid - rid
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+idmap_get_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
+ char **sidprefix, idmap_rid_t *rid, idmap_stat *stat) {
+
+ idmap_retcode retcode;
+ idmap_mapping *mapping;
+
+ /* sanity checks */
+ if (gh == NULL)
+ return (IDMAP_ERR_ARG);
+ if (sidprefix == NULL)
+ return (IDMAP_ERR_ARG);
+
+ /* Extend the request array and the return list */
+ if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
+ goto errout;
+
+ /* Setup the request */
+ mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
+ mapping->flag = flag;
+ mapping->id1.idtype = IDMAP_UID;
+ mapping->id1.idmap_id_u.uid = uid;
+ mapping->id2.idtype = IDMAP_SID;
+
+ /* Setup pointers for the result */
+ gh->retlist[gh->next].idtype = IDMAP_SID;
+ gh->retlist[gh->next].sidprefix = sidprefix;
+ gh->retlist[gh->next].rid = rid;
+ gh->retlist[gh->next].stat = stat;
+
+ gh->next++;
+ return (IDMAP_SUCCESS);
+
+errout:
+ (void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
+ free(gh->retlist);
+ gh->retlist = NULL;
+ gh->next = 0;
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Given GID, get SID
+ *
+ * Input:
+ * gid - POSIX GID
+ * flag - flag
+ *
+ * Output:
+ * stat - status of the get request
+ * sidprefix - SID prefix (if stat == 0)
+ * rid - rid
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+idmap_get_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
+ char **sidprefix, idmap_rid_t *rid, idmap_stat *stat) {
+
+ idmap_retcode retcode;
+ idmap_mapping *mapping;
+
+ /* sanity checks */
+ if (gh == NULL)
+ return (IDMAP_ERR_ARG);
+ if (sidprefix == NULL)
+ return (IDMAP_ERR_ARG);
+
+ /* Extend the request array and the return list */
+ if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
+ goto errout;
+
+ /* Setup the request */
+ mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
+ mapping->flag = flag;
+ mapping->id1.idtype = IDMAP_GID;
+ mapping->id1.idmap_id_u.gid = gid;
+ mapping->id2.idtype = IDMAP_SID;
+
+ /* Setup pointers for the result */
+ gh->retlist[gh->next].idtype = IDMAP_SID;
+ gh->retlist[gh->next].sidprefix = sidprefix;
+ gh->retlist[gh->next].rid = rid;
+ gh->retlist[gh->next].stat = stat;
+
+ gh->next++;
+ return (IDMAP_SUCCESS);
+
+errout:
+ (void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
+ free(gh->retlist);
+ gh->retlist = NULL;
+ gh->next = 0;
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Process the batched "get mapping" requests. The results (i.e.
+ * status and identity) will be available in the data areas
+ * provided by individual requests.
+ */
+idmap_stat
+idmap_get_mappings(idmap_get_handle_t *gh) {
+ CLIENT *clnt;
+ enum clnt_stat clntstat;
+ idmap_retcode retcode;
+ idmap_ids_res res;
+ idmap_id *id;
+ int i;
+
+ if (gh == NULL) {
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+ _IDMAP_GET_CLIENT_HANDLE(gh->ih, clnt);
+
+ (void) memset(&res, 0, sizeof (idmap_ids_res));
+ clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_IDS,
+ (xdrproc_t)xdr_idmap_mapping_batch,
+ (caddr_t)&gh->batch,
+ (xdrproc_t)xdr_idmap_ids_res,
+ (caddr_t)&res,
+ TIMEOUT);
+ if (clntstat != RPC_SUCCESS) {
+ if (__idmap_verbose)
+ clnt_perror(clnt, "IDMAP_GET_MAPPED_IDS");
+ retcode = IDMAP_ERR_RPC;
+ goto out;
+ }
+ if (res.retcode != IDMAP_SUCCESS) {
+ retcode = res.retcode;
+ goto out;
+ }
+ for (i = 0; i < gh->next; i++) {
+ if (i >= res.ids.ids_len) {
+ *gh->retlist[i].stat = IDMAP_ERR_NORESULT;
+ continue;
+ }
+ *gh->retlist[i].stat = res.ids.ids_val[i].retcode;
+ id = &res.ids.ids_val[i].id;
+ switch (id->idtype) {
+ case IDMAP_UID:
+ if (gh->retlist[i].uid)
+ *gh->retlist[i].uid = id->idmap_id_u.uid;
+ if (gh->retlist[i].is_user)
+ *gh->retlist[i].is_user = 1;
+ break;
+ case IDMAP_GID:
+ if (gh->retlist[i].gid)
+ *gh->retlist[i].gid = id->idmap_id_u.gid;
+ if (gh->retlist[i].is_user)
+ *gh->retlist[i].is_user = 0;
+ break;
+ case IDMAP_SID:
+ if (gh->retlist[i].rid)
+ *gh->retlist[i].rid = id->idmap_id_u.sid.rid;
+ if (gh->retlist[i].sidprefix) {
+ if (id->idmap_id_u.sid.prefix == NULL) {
+ *gh->retlist[i].sidprefix = NULL;
+ break;
+ }
+ *gh->retlist[i].sidprefix =
+ strdup(id->idmap_id_u.sid.prefix);
+ if (*gh->retlist[i].sidprefix == NULL)
+ *gh->retlist[i].stat =
+ IDMAP_ERR_MEMORY;
+ }
+ break;
+ case IDMAP_NONE:
+ break;
+ default:
+ *gh->retlist[i].stat = IDMAP_ERR_NORESULT;
+ break;
+ }
+ }
+ retcode = IDMAP_SUCCESS;
+
+out:
+ (void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
+ free(gh->retlist);
+ gh->retlist = NULL;
+ gh->next = 0;
+ (void) xdr_free(xdr_idmap_ids_res, (caddr_t)&res);
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Destroy the "get mapping" handle
+ */
+void
+idmap_get_destroy(idmap_get_handle_t *gh) {
+ if (gh == NULL)
+ return;
+ (void) xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
+ if (gh->retlist)
+ free(gh->retlist);
+ free(gh);
+}
+
+
+/*
+ * Get windows to unix mapping
+ */
+idmap_stat
+idmap_get_w2u_mapping(idmap_handle_t *handle,
+ const char *sidprefix, idmap_rid_t *rid,
+ const char *winname, const char *windomain,
+ int flag, int *is_user,
+ uid_t *pid, char **unixname, int *direction) {
+ CLIENT *clnt;
+ enum clnt_stat clntstat;
+ idmap_mapping request, *mapping;
+ idmap_mappings_res result;
+ idmap_retcode retcode, rc;
+ idmap_utf8str *str;
+ const char *me = "idmap_get_w2u_mapping";
+
+ if (handle == NULL) {
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("%s: Invalid handle\n"), me);
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+
+ _IDMAP_GET_CLIENT_HANDLE(handle, clnt);
+
+ (void) memset(&request, 0, sizeof (request));
+ (void) memset(&result, 0, sizeof (result));
+
+ if (pid)
+ *pid = UINT32_MAX;
+ if (unixname)
+ *unixname = NULL;
+ if (direction)
+ *direction = -1;
+
+ request.flag = flag;
+ request.id1.idtype = IDMAP_SID;
+ if (sidprefix && rid) {
+ request.id1.idmap_id_u.sid.prefix = (char *)sidprefix;
+ request.id1.idmap_id_u.sid.rid = *rid;
+ } else if (winname) {
+ str = &request.id1name;
+ retcode = idmap_str2utf8(&str, winname, 1);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+ if (windomain) {
+ str = &request.id1domain;
+ retcode = idmap_str2utf8(&str, windomain, 1);
+ if (retcode != IDMAP_SUCCESS)
+ return (retcode);
+ }
+ request.id1.idmap_id_u.sid.prefix = NULL;
+ } else {
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+
+ if (is_user == NULL)
+ request.id2.idtype = IDMAP_POSIXID;
+ else if (*is_user == 1)
+ request.id2.idtype = IDMAP_UID;
+ else if (*is_user == 0)
+ request.id2.idtype = IDMAP_GID;
+ else
+ request.id2.idtype = IDMAP_POSIXID;
+
+ clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
+ (xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
+ (xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
+ TIMEOUT);
+
+ if (clntstat != RPC_SUCCESS) {
+ if (__idmap_verbose)
+ clnt_perror(clnt, "IDMAP_GET_MAPPED_ID_BY_NAME");
+ return (IDMAP_ERR_RPC);
+ }
+
+ retcode = result.retcode;
+
+ if ((mapping = result.mappings.mappings_val) == NULL) {
+ if (retcode == IDMAP_SUCCESS)
+ retcode = IDMAP_ERR_NORESULT;
+ goto out;
+ }
+
+ if (is_user)
+ *is_user = (mapping->id2.idtype == IDMAP_UID)?1:0;
+ if (direction)
+ *direction = mapping->direction;
+ if (pid)
+ *pid = mapping->id2.idmap_id_u.uid;
+ if (unixname) {
+ rc = idmap_utf82str(unixname, 0, &mapping->id2name);
+ if (rc != IDMAP_SUCCESS)
+ retcode = rc;
+ }
+
+out:
+ xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
+ if (retcode != IDMAP_SUCCESS)
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * Get unix to windows mapping
+ */
+idmap_stat
+idmap_get_u2w_mapping(idmap_handle_t *handle,
+ uid_t *pid, const char *unixname,
+ int flag, int is_user,
+ char **sidprefix, idmap_rid_t *rid,
+ char **winname, char **windomain,
+ int *direction) {
+ CLIENT *clnt;
+ enum clnt_stat clntstat;
+ idmap_mapping request, *mapping;
+ idmap_mappings_res result;
+ idmap_retcode retcode, rc;
+ idmap_utf8str *str;
+ const char *me = "idmap_get_u2w_mapping";
+
+ if (handle == NULL) {
+ if (__idmap_verbose)
+ (void) fprintf(stderr,
+ gettext("%s: Invalid handle\n"), me);
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+
+ _IDMAP_GET_CLIENT_HANDLE(handle, clnt);
+
+ if (sidprefix)
+ *sidprefix = NULL;
+ if (winname)
+ *winname = NULL;
+ if (windomain)
+ *windomain = NULL;
+ if (rid)
+ *rid = UINT32_MAX;
+ if (direction)
+ *direction = -1;
+
+ (void) memset(&request, 0, sizeof (request));
+ (void) memset(&result, 0, sizeof (result));
+
+ request.flag = flag;
+ request.id1.idtype = is_user?IDMAP_UID:IDMAP_GID;
+
+ if (pid && *pid != UINT32_MAX) {
+ request.id1.idmap_id_u.uid = *pid;
+ } else if (unixname) {
+ str = &request.id1name;
+ retcode = idmap_str2utf8(&str, unixname, 1);
+ if (retcode != IDMAP_SUCCESS)
+ goto out;
+ request.id1.idmap_id_u.uid = UINT32_MAX;
+ } else {
+ errno = EINVAL;
+ return (IDMAP_ERR_ARG);
+ }
+
+ request.id2.idtype = IDMAP_SID;
+
+ clntstat = clnt_call(clnt, IDMAP_GET_MAPPED_ID_BY_NAME,
+ (xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
+ (xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
+ TIMEOUT);
+
+ if (clntstat != RPC_SUCCESS) {
+ if (__idmap_verbose)
+ clnt_perror(clnt, "IDMAP_GET_MAPPED_ID_BY_NAME");
+ return (IDMAP_ERR_RPC);
+ }
+
+ retcode = result.retcode;
+
+ if ((mapping = result.mappings.mappings_val) == NULL) {
+ if (retcode == IDMAP_SUCCESS)
+ retcode = IDMAP_ERR_NORESULT;
+ goto out;
+ }
+
+ if (direction)
+ *direction = mapping->direction;
+ if (sidprefix) {
+ *sidprefix = strdup(mapping->id2.idmap_id_u.sid.prefix);
+ if (*sidprefix == NULL) {
+ retcode = IDMAP_ERR_MEMORY;
+ goto errout;
+ }
+ }
+ if (rid)
+ *rid = mapping->id2.idmap_id_u.sid.rid;
+ if (winname) {
+ rc = idmap_utf82str(winname, 0, &mapping->id2name);
+ if (rc != IDMAP_SUCCESS) {
+ retcode = rc;
+ goto errout;
+ }
+ }
+ if (windomain) {
+ rc = idmap_utf82str(windomain, 0, &mapping->id2domain);
+ if (rc != IDMAP_SUCCESS) {
+ retcode = rc;
+ goto errout;
+ }
+ }
+
+ goto out;
+
+errout:
+ if (sidprefix && *sidprefix) {
+ free(*sidprefix);
+ *sidprefix = NULL;
+ }
+ if (winname && *winname) {
+ free(*winname);
+ *winname = NULL;
+ }
+ if (windomain && *windomain) {
+ free(*windomain);
+ *windomain = NULL;
+ }
+
+out:
+ xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
+ if (retcode != IDMAP_SUCCESS)
+ errno = idmap_stat2errno(retcode);
+ return (retcode);
+}
+
+
+/*
+ * utf8str to string
+ */
+idmap_stat
+idmap_utf82str(char **out, size_t outsize, idmap_utf8str *in) {
+ int len;
+
+ if (in == NULL || out == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (outsize == 0) {
+ *out = NULL;
+ if ((len = in->idmap_utf8str_len) == 0)
+ return (IDMAP_SUCCESS);
+ if (in->idmap_utf8str_val == NULL)
+ return (IDMAP_ERR_ARG);
+ if (in->idmap_utf8str_val[len - 1] != 0)
+ len++;
+ *out = calloc(1, len);
+ if (*out == NULL)
+ return (IDMAP_ERR_MEMORY);
+ } else {
+ if (*out == NULL)
+ return (IDMAP_ERR_ARG);
+ (void) memset(*out, 0, outsize);
+ if ((len = in->idmap_utf8str_len) == 0)
+ return (IDMAP_SUCCESS);
+ if (in->idmap_utf8str_val == NULL)
+ return (IDMAP_ERR_ARG);
+ if (in->idmap_utf8str_val[len - 1] != 0)
+ len++;
+ if (outsize < len)
+ return (IDMAP_ERR_ARG);
+ }
+ (void) memcpy(*out, in->idmap_utf8str_val, in->idmap_utf8str_len);
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * string to utf8str
+ */
+idmap_stat
+idmap_str2utf8(idmap_utf8str **out, const char *in, int flag) {
+ idmap_utf8str *tmp;
+
+ if (out == NULL)
+ return (IDMAP_ERR_ARG);
+ else if (*out == NULL) {
+ tmp = malloc(sizeof (idmap_utf8str));
+ if (tmp == NULL)
+ return (IDMAP_ERR_MEMORY);
+ } else {
+ tmp = *out;
+ }
+
+ if (in == NULL) {
+ tmp->idmap_utf8str_len = 0;
+ tmp->idmap_utf8str_val = NULL;
+ if (*out == NULL)
+ *out = tmp;
+ return (IDMAP_SUCCESS);
+ }
+
+ /* include the null terminator */
+ tmp->idmap_utf8str_len = strlen(in) + 1;
+
+ if (flag == 1) {
+ /* Don't malloc, simply assign */
+ tmp->idmap_utf8str_val = (char *)in;
+ if (*out == NULL)
+ *out = tmp;
+ return (IDMAP_SUCCESS);
+ }
+
+ tmp->idmap_utf8str_val = malloc(tmp->idmap_utf8str_len);
+ if (tmp->idmap_utf8str_val == NULL) {
+ tmp->idmap_utf8str_len = 0;
+ if (*out == NULL)
+ free(tmp);
+ return (IDMAP_ERR_MEMORY);
+ }
+ (void) memcpy(tmp->idmap_utf8str_val, in, tmp->idmap_utf8str_len);
+ if (*out == NULL)
+ *out = tmp;
+ return (IDMAP_SUCCESS);
+}
+
+
+#define gettext(s) s
+static stat_table_t stattable[] = {
+ {IDMAP_SUCCESS, gettext("Success"), 0},
+ {IDMAP_NEXT, gettext("More results available"), 0},
+ {IDMAP_ERR_OTHER, gettext("Undefined error"), EINVAL},
+ {IDMAP_ERR_INTERNAL, gettext("Internal error"), EINVAL},
+ {IDMAP_ERR_MEMORY, gettext("Out of memory"), ENOMEM},
+ {IDMAP_ERR_NORESULT, gettext("No results available"), EINVAL},
+ {IDMAP_ERR_NOTUSER, gettext("Not a user"), EINVAL},
+ {IDMAP_ERR_NOTGROUP, gettext("Not a group"), EINVAL},
+ {IDMAP_ERR_NOTSUPPORTED, gettext("Operation not supported"), EINVAL},
+ {IDMAP_ERR_W2U_NAMERULE,
+ gettext("Invalid Windows to UNIX name-based rule"), EINVAL},
+ {IDMAP_ERR_U2W_NAMERULE,
+ gettext("Invalid UNIX to Windows name-based rule"), EINVAL},
+ {IDMAP_ERR_CACHE, gettext("Invalid cache"), EINVAL},
+ {IDMAP_ERR_DB, gettext("Invalid database"), EINVAL},
+ {IDMAP_ERR_ARG, gettext("Invalid argument"), EINVAL},
+ {IDMAP_ERR_SID, gettext("Invalid SID"), EINVAL},
+ {IDMAP_ERR_IDTYPE, gettext("Invalid identity type"), EINVAL},
+ {IDMAP_ERR_RPC_HANDLE, gettext("Bad RPC handle"), EINVAL},
+ {IDMAP_ERR_RPC, gettext("RPC error"), EINVAL},
+ {IDMAP_ERR_CLIENT_HANDLE, gettext("Bad client handle"), EINVAL},
+ {IDMAP_ERR_BUSY, gettext("Server is busy"), EINVAL},
+ {IDMAP_ERR_PERMISSION_DENIED, gettext("Permisssion denied"), EINVAL},
+ {IDMAP_ERR_NOMAPPING,
+ gettext("Mapping not found or inhibited"), EINVAL},
+ {IDMAP_ERR_NEW_ID_ALLOC_REQD,
+ gettext("New mapping needs to be created"), EINVAL},
+ {IDMAP_ERR_DOMAIN, gettext("Invalid domain"), EINVAL},
+ {IDMAP_ERR_SECURITY, gettext("Security issue"), EINVAL},
+ {IDMAP_ERR_NOTFOUND, gettext("Not found"), EINVAL},
+ {IDMAP_ERR_DOMAIN_NOTFOUND, gettext("Domain not found"), EINVAL},
+ {IDMAP_ERR_UPDATE_NOTALLOWED, gettext("Update not allowed"), EINVAL},
+ {IDMAP_ERR_CFG, gettext("Configuration error"), EINVAL},
+ {IDMAP_ERR_CFG_CHANGE, gettext("Invalid configuration change"), EINVAL},
+ {IDMAP_ERR_NOTMAPPED_WELLKNOWN,
+ gettext("No mapping for well-known SID"), EINVAL},
+ {IDMAP_ERR_RETRIABLE_NET_ERR,
+ gettext("Network error"), EINVAL},
+ {-1, NULL, 0}
+};
+#undef gettext
+
+
+/*
+ * Get description of status code
+ *
+ * Input:
+ * status - Status code returned by libidmap API call
+ *
+ * Return Value:
+ * human-readable localized description of idmap_stat
+ */
+/* ARGSUSED */
+const char *
+idmap_stat2string(idmap_handle_t *handle, idmap_stat status) {
+ int i;
+
+ for (i = 0; stattable[i].msg; i++) {
+ if (stattable[i].retcode == status)
+ return (stattable[i].msg);
+ }
+ return (gettext("Unknown error"));
+}
+
+
+static int
+idmap_stat2errno(idmap_stat stat) {
+ int i;
+ for (i = 0; stattable[i].msg; i++) {
+ if (stattable[i].retcode == stat)
+ return (stattable[i].errnum);
+ }
+ return (EINVAL);
+}
+
+
+/*
+ * Get status code from string
+ */
+idmap_stat
+idmap_string2stat(const char *str) {
+ if (str == NULL)
+ return (IDMAP_ERR_INTERNAL);
+
+#define return_cmp(a) \
+ if (0 == strcmp(str, "IDMAP_ERR_" #a)) \
+ return (IDMAP_ERR_ ## a);
+
+ return_cmp(OTHER);
+ return_cmp(INTERNAL);
+ return_cmp(MEMORY);
+ return_cmp(NORESULT);
+ return_cmp(NOTUSER);
+ return_cmp(NOTGROUP);
+ return_cmp(NOTSUPPORTED);
+ return_cmp(W2U_NAMERULE);
+ return_cmp(U2W_NAMERULE);
+ return_cmp(CACHE);
+ return_cmp(DB);
+ return_cmp(ARG);
+ return_cmp(SID);
+ return_cmp(IDTYPE);
+ return_cmp(RPC_HANDLE);
+ return_cmp(RPC);
+ return_cmp(CLIENT_HANDLE);
+ return_cmp(BUSY);
+ return_cmp(PERMISSION_DENIED);
+ return_cmp(NOMAPPING);
+ return_cmp(NEW_ID_ALLOC_REQD);
+ return_cmp(DOMAIN);
+ return_cmp(SECURITY);
+ return_cmp(NOTFOUND);
+ return_cmp(DOMAIN_NOTFOUND);
+ return_cmp(MEMORY);
+ return_cmp(UPDATE_NOTALLOWED);
+ return_cmp(CFG);
+ return_cmp(CFG_CHANGE);
+ return_cmp(NOTMAPPED_WELLKNOWN);
+ return_cmp(RETRIABLE_NET_ERR);
+#undef return_cmp
+
+ return (IDMAP_ERR_OTHER);
+}
+
+
+/*
+ * Map the given status to one that can be returned by the protocol
+ */
+idmap_stat
+idmap_stat4prot(idmap_stat status) {
+ switch (status) {
+ case IDMAP_ERR_MEMORY:
+ case IDMAP_ERR_CACHE:
+ return (IDMAP_ERR_INTERNAL);
+ }
+ return (status);
+}
diff --git a/usr/src/lib/libidmap/common/idmap_impl.h b/usr/src/lib/libidmap/common/idmap_impl.h
new file mode 100644
index 0000000000..858654957d
--- /dev/null
+++ b/usr/src/lib/libidmap/common/idmap_impl.h
@@ -0,0 +1,113 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Private Header for Identity Mapping
+ */
+
+#ifndef _IDMAP_IMPL_H
+#define _IDMAP_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "idmap_prot.h"
+#include "idmap_priv.h"
+#include <rpc/xdr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _IDMAP_HANDLE_RPC_DOORS 1
+
+#define _IDMAP_GET_CLIENT_HANDLE(h, clnt) \
+ if (h == NULL) \
+ return (IDMAP_ERR_CLIENT_HANDLE);\
+ if (h->type != _IDMAP_HANDLE_RPC_DOORS) \
+ return (IDMAP_ERR_NOTSUPPORTED);\
+ clnt = (CLIENT *)h->privhandle;\
+ if (clnt == NULL)\
+ return (IDMAP_ERR_RPC_HANDLE);
+
+struct idmap_handle {
+ int type;
+ void *privhandle;
+ /* locks */
+};
+
+struct idmap_udt_handle {
+ struct idmap_handle *ih;
+ idmap_update_batch batch;
+ uint64_t next;
+ char *lastmsg;
+};
+
+typedef struct idmap_get_res {
+ idmap_id_type idtype;
+ uid_t *uid;
+ gid_t *gid;
+ int *is_user;
+ char **sidprefix;
+ idmap_rid_t *rid;
+ idmap_stat *stat;
+} idmap_get_res_t;
+
+struct idmap_get_handle {
+ struct idmap_handle *ih;
+ idmap_mapping_batch batch;
+ idmap_get_res_t *retlist;
+ uint64_t next;
+ char *lastmsg;
+};
+
+struct idmap_iter {
+ struct idmap_handle *ih;
+ int type;
+ uint64_t limit;
+ void *arg;
+ idmap_retcode retcode;
+ uint64_t lastrowid;
+ uint64_t next;
+ void *retlist;
+};
+
+typedef struct stat_table {
+ idmap_retcode retcode;
+ const char *msg;
+ int errnum;
+} stat_table_t;
+
+typedef idmap_retcode _idmap_stat;
+
+extern idmap_retcode _udt_extend_batch(idmap_udt_handle_t *, int);
+extern idmap_retcode _get_ids_extend_batch(idmap_get_handle_t *);
+extern idmap_stat _iter_get_next_list(int, idmap_iter_t *, void *,
+ uchar_t **, size_t, xdrproc_t, xdrproc_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IDMAP_IMPL_H */
diff --git a/usr/src/lib/libidmap/common/idmap_priv.h b/usr/src/lib/libidmap/common/idmap_priv.h
new file mode 100644
index 0000000000..9b00b8f380
--- /dev/null
+++ b/usr/src/lib/libidmap/common/idmap_priv.h
@@ -0,0 +1,143 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Additional API for Identity Mapping Service
+ */
+
+#ifndef _IDMAP_PRIV_H
+#define _IDMAP_PRIV_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "idmap.h"
+#include "idmap_prot.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IDMAP_MAX_NAME_LEN 512
+
+#define IDMAP_ERROR(rc) rc != IDMAP_SUCCESS && rc != IDMAP_NEXT
+#define IDMAP_FATAL_ERROR(rc) rc == IDMAP_ERR_MEMORY ||\
+ rc == IDMAP_ERR_DB
+
+/* Opaque handle to batch config add/remove operations */
+typedef struct idmap_udt_handle idmap_udt_handle_t;
+
+/* Opaque iterator */
+typedef struct idmap_iter idmap_iter_t;
+
+
+/*
+ * Update API
+ */
+
+/* Create handle for updates */
+extern idmap_stat idmap_udt_create(idmap_handle_t *,
+ idmap_udt_handle_t **);
+
+/* Commit */
+extern idmap_stat idmap_udt_commit(idmap_udt_handle_t *);
+
+/* Destroy the update handle */
+extern void idmap_udt_destroy(idmap_udt_handle_t *);
+
+/* Add name-based mapping rule */
+extern idmap_stat idmap_udt_add_namerule(idmap_udt_handle_t *, const char *,
+ boolean_t, const char *, const char *, boolean_t, int);
+
+/* Remove name-based mapping rule */
+extern idmap_stat idmap_udt_rm_namerule(idmap_udt_handle_t *, boolean_t,
+ const char *, const char *, const char *, int);
+
+/* Flush name-based mapping rules */
+extern idmap_stat idmap_udt_flush_namerules(idmap_udt_handle_t *, boolean_t);
+
+
+/*
+ * Iterator API
+ */
+
+/* Create a iterator to get SID to UID/GID mappings */
+extern idmap_stat idmap_iter_mappings(idmap_handle_t *, boolean_t,
+ idmap_iter_t **);
+
+/* Iterate through the SID to UID/GID mappings */
+extern idmap_stat idmap_iter_next_mapping(idmap_iter_t *, char **,
+ idmap_rid_t *, uid_t *, char **, char **, char **, int *);
+
+/* Create a iterator to get name-based mapping rules */
+extern idmap_stat idmap_iter_namerules(idmap_handle_t *, const char *,
+ boolean_t, const char *, const char *, idmap_iter_t **);
+
+/* Iterate through the name-based mapping rules */
+extern idmap_stat idmap_iter_next_namerule(idmap_iter_t *, char **,
+ char **, char **, boolean_t *, int *);
+
+/* Set the number of entries requested per batch */
+extern idmap_stat idmap_iter_set_limit(idmap_iter_t *, uint64_t);
+
+/* Destroy the iterator */
+extern void idmap_iter_destroy(idmap_iter_t *);
+
+
+/*
+ * Get mapping
+ */
+extern idmap_stat idmap_get_w2u_mapping(idmap_handle_t *, const char *,
+ idmap_rid_t *, const char *, const char *, int, int *,
+ uid_t *, char **, int *);
+
+extern idmap_stat idmap_get_u2w_mapping(idmap_handle_t *, uid_t *,
+ const char *, int, int, char **, idmap_rid_t *, char **,
+ char **, int *);
+
+
+/*
+ * Miscellaneous
+ */
+
+/* utf8 to string */
+extern idmap_stat idmap_utf82str(char **, size_t, idmap_utf8str *);
+
+/* string to utf8 */
+extern idmap_stat idmap_str2utf8(idmap_utf8str **, const char *, int);
+
+/* string to status */
+extern idmap_stat idmap_string2stat(const char *);
+
+/* internal status to protocol status */
+extern idmap_stat idmap_stat4prot(idmap_stat);
+
+/* enable/disable verbose mode for API */
+extern void idmap_set_verbose(boolean_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IDMAP_PRIV_H */
diff --git a/usr/src/lib/libidmap/common/llib-lidmap b/usr/src/lib/libidmap/common/llib-lidmap
new file mode 100644
index 0000000000..00e22d3edc
--- /dev/null
+++ b/usr/src/lib/libidmap/common/llib-lidmap
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include "idmap_impl.h"
diff --git a/usr/src/lib/libidmap/common/mapfile-vers b/usr/src/lib/libidmap/common/mapfile-vers
new file mode 100644
index 0000000000..e39a1962bb
--- /dev/null
+++ b/usr/src/lib/libidmap/common/mapfile-vers
@@ -0,0 +1,74 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate {
+ global:
+ xdr_idmap_utf8str;
+ xdr_idmap_retcode;
+ xdr_idmap_namerule;
+ xdr_idmap_namerules_res;
+ xdr_idmap_ids_res;
+ xdr_idmap_mapping_batch;
+ xdr_idmap_list_mappings_1_argument;
+ xdr_idmap_mappings_res;
+ xdr_idmap_update_batch;
+ xdr_idmap_list_namerules_1_argument;
+ xdr_idmap_mapping;
+ xdr_idmap_id_res;
+ idmap_init;
+ idmap_fini;
+ idmap_free;
+ idmap_stat2string;
+ idmap_string2stat;
+ idmap_stat4prot;
+ idmap_set_verbose;
+ idmap_str2utf8;
+ idmap_utf82str;
+ idmap_iter_namerules;
+ idmap_iter_next_namerule;
+ idmap_iter_mappings;
+ idmap_iter_next_mapping;
+ idmap_iter_destroy;
+ idmap_get_create;
+ idmap_get_uidbysid;
+ idmap_get_gidbysid;
+ idmap_get_pidbysid;
+ idmap_get_sidbyuid;
+ idmap_get_sidbygid;
+ idmap_get_mappings;
+ idmap_get_destroy;
+ idmap_get_w2u_mapping;
+ idmap_get_u2w_mapping;
+ idmap_udt_add_namerule;
+ idmap_udt_rm_namerule;
+ idmap_udt_destroy;
+ idmap_udt_commit;
+ idmap_udt_create;
+ idmap_udt_flush_namerules;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libidmap/common/utils.c b/usr/src/lib/libidmap/common/utils.c
new file mode 100644
index 0000000000..cf0755f0ae
--- /dev/null
+++ b/usr/src/lib/libidmap/common/utils.c
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Utility routines
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <libintl.h>
+#include "idmap_impl.h"
+
+#define _UDT_SIZE_INCR 1
+
+#define _GET_IDS_SIZE_INCR 1
+
+static struct timeval TIMEOUT = { 25, 0 };
+
+extern int __idmap_verbose;
+
+idmap_retcode
+_udt_extend_batch(idmap_udt_handle_t *udthandle, int opnum) {
+ idmap_update_op *tmplist;
+ size_t nsize;
+
+ if (udthandle->next >= udthandle->batch.idmap_update_batch_len) {
+ nsize = (udthandle->batch.idmap_update_batch_len +
+ _UDT_SIZE_INCR) * sizeof (*tmplist);
+ tmplist = realloc(
+ udthandle->batch.idmap_update_batch_val, nsize);
+ if (tmplist == NULL)
+ return (IDMAP_ERR_MEMORY);
+ (void) memset((uchar_t *)tmplist +
+ (udthandle->batch.idmap_update_batch_len *
+ sizeof (*tmplist)), 0,
+ _UDT_SIZE_INCR * sizeof (*tmplist));
+ udthandle->batch.idmap_update_batch_val = tmplist;
+ udthandle->batch.idmap_update_batch_len += _UDT_SIZE_INCR;
+ }
+ udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
+ opnum;
+ return (IDMAP_SUCCESS);
+}
+
+idmap_retcode
+_get_ids_extend_batch(idmap_get_handle_t *gh) {
+ idmap_mapping *t1;
+ idmap_get_res_t *t2;
+ size_t nsize, len;
+
+ len = gh->batch.idmap_mapping_batch_len;
+ if (gh->next >= len) {
+ /* extend the request array */
+ nsize = (len + _GET_IDS_SIZE_INCR) * sizeof (*t1);
+ t1 = realloc(gh->batch.idmap_mapping_batch_val, nsize);
+ if (t1 == NULL)
+ return (IDMAP_ERR_MEMORY);
+ (void) memset((uchar_t *)t1 + (len * sizeof (*t1)), 0,
+ _GET_IDS_SIZE_INCR * sizeof (*t1));
+ gh->batch.idmap_mapping_batch_val = t1;
+
+ /* extend the return list */
+ nsize = (len + _GET_IDS_SIZE_INCR) * sizeof (*t2);
+ t2 = realloc(gh->retlist, nsize);
+ if (t2 == NULL)
+ return (IDMAP_ERR_MEMORY);
+ (void) memset((uchar_t *)t2 + (len * sizeof (*t2)), 0,
+ _GET_IDS_SIZE_INCR * sizeof (*t2));
+ gh->retlist = t2;
+
+ gh->batch.idmap_mapping_batch_len += _GET_IDS_SIZE_INCR;
+ }
+ return (IDMAP_SUCCESS);
+}
+
+idmap_stat
+_iter_get_next_list(int type, idmap_iter_t *iter,
+ void *arg, uchar_t **list, size_t valsize,
+ xdrproc_t xdr_arg_proc, xdrproc_t xdr_res_proc) {
+
+ CLIENT *clnt;
+ enum clnt_stat clntstat;
+ const char *me = "_iter_get_next_list";
+
+ if (__idmap_verbose)
+ (void) fprintf(stdout, "%s\n", me);
+
+ iter->next = 0;
+ iter->retlist = NULL;
+ _IDMAP_GET_CLIENT_HANDLE(iter->ih, clnt);
+
+ /* init the result */
+ if (*list) {
+ xdr_free(xdr_res_proc, (caddr_t)*list);
+ } else {
+ if ((*list = malloc(valsize)) == NULL) {
+ (void) fprintf(stderr, gettext("Out of memory\n"));
+ errno = ENOMEM;
+ return (IDMAP_ERR_MEMORY);
+ }
+ }
+ (void) memset(*list, 0, valsize);
+
+ clntstat = clnt_call(clnt, type,
+ xdr_arg_proc, (caddr_t)arg,
+ xdr_res_proc, (caddr_t)*list,
+ TIMEOUT);
+ if (clntstat != RPC_SUCCESS) {
+ free(*list);
+ if (__idmap_verbose)
+ clnt_perror(clnt, me);
+ return (IDMAP_ERR_RPC);
+ }
+ iter->retlist = *list;
+ return (IDMAP_SUCCESS);
+}
diff --git a/usr/src/lib/libidmap/i386/Makefile b/usr/src/lib/libidmap/i386/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/libidmap/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libidmap/sparc/Makefile b/usr/src/lib/libidmap/sparc/Makefile
new file mode 100644
index 0000000000..f91f0270e9
--- /dev/null
+++ b/usr/src/lib/libidmap/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libidmap/sparcv9/Makefile b/usr/src/lib/libidmap/sparcv9/Makefile
new file mode 100644
index 0000000000..7c17fe3827
--- /dev/null
+++ b/usr/src/lib/libidmap/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt
index 44a459df85..536da81d16 100644
--- a/usr/src/lib/libsecdb/auth_attr.txt
+++ b/usr/src/lib/libsecdb/auth_attr.txt
@@ -30,6 +30,8 @@
solaris.:::All Solaris Authorizations::help=AllSolAuthsHeader.html
solaris.grant:::Grant All Solaris Authorizations::help=PriAdmin.html
#
+solaris.admin.idmap.rules:::Manage Identity Mapping Rules::help=IdmapRules.html
+#
solaris.audit.:::Audit Management::help=AuditHeader.html
solaris.audit.config:::Configure Auditing::help=AuditConfig.html
solaris.audit.read:::Read Audit Trail::help=AuditRead.html
@@ -90,6 +92,7 @@ solaris.smf.manage.bind:::Manage DNS Service States::help=BindStates.html
solaris.smf.manage.cron:::Manage Cron Service States::help=SmfCronStates.html
solaris.smf.manage.hal:::Manage HAL Service States::help=SmfHALStates.html
solaris.smf.manage.ipsec:::Manage IPsec Service States::help=SmfIPsecStates.html
+solaris.smf.manage.idmap:::Manage Identity Mapping Service States::help=SmfIdmapStates.html
solaris.smf.manage.name-service-cache:::Manage Name Service Cache Daemon Service States::help=SmfNscdStates.html
solaris.smf.manage.nwam:::Manage Network Auto-Magic Service States::help=SmfNWAMStates.html
solaris.smf.manage.power:::Manage Power Management Service States::help=SmfPowerStates.html
@@ -104,6 +107,7 @@ solaris.smf.value.:::Change Values of SMF Service Properties::help=SmfValueHeade
solaris.smf.value.ipsec:::Change Values of SMF IPsec Properties::help=SmfValueIPsec.html
solaris.smf.value.nwam:::Change Values of SMF Network Auto-Magic Properties::help=SmfValueNWAM.html
solaris.smf.value.routing:::Change Values of SMF Routing Properties::help=SmfValueRouting.html
+solaris.smf.value.idmap:::Change Values of SMF Identity Mapping Service Properties::help=SmfValueIdmap.html
#
solaris.system.:::Machine Administration::help=SysHeader.html
solaris.system.date:::Set Date & Time::help=SysDate.html
diff --git a/usr/src/lib/libsecdb/help/auths/IdmapRules.html b/usr/src/lib/libsecdb/help/auths/IdmapRules.html
new file mode 100644
index 0000000000..76a712eea2
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/IdmapRules.html
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+-->
+<!-- SCCS keyword
+#ident "%Z%%M% %I% %E% SMI"
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Manage Identity Mapping Rules is in the Authorizations Include
+column, it grants the authorization to add and remove mapping rules of
+Identity Mapping service.
+<p>
+If Manage Identity Mapping Rules is grayed, then you are not entitled
+to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile
index 293067a706..71882e6851 100644
--- a/usr/src/lib/libsecdb/help/auths/Makefile
+++ b/usr/src/lib/libsecdb/help/auths/Makefile
@@ -90,7 +90,10 @@ HTMLENTS = \
NetworkHeader.html \
WifiConfig.html \
WifiWep.html \
- LinkSecurity.html
+ LinkSecurity.html \
+ IdmapRules.html \
+ SmfIdmapStates.html \
+ SmfValueIdmap.html
HELPDIR=$(ROOT)/usr/lib/help
AUTHDIR=$(HELPDIR)/auths
diff --git a/usr/src/lib/libsecdb/help/auths/SmfIdmapStates.html b/usr/src/lib/libsecdb/help/auths/SmfIdmapStates.html
new file mode 100644
index 0000000000..53ff17a286
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/SmfIdmapStates.html
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+-->
+<!-- SCCS keyword
+#ident "%Z%%M% %I% %E% SMI"
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Manage Identity Mapping Service States is in the Authorizations Include
+column, it grants the authorization to enable, disable, or restart
+Identity Mapping service.
+<p>
+If Manage Identity Mapping Service States is grayed, then you are not entitled
+to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/auths/SmfValueIdmap.html b/usr/src/lib/libsecdb/help/auths/SmfValueIdmap.html
new file mode 100644
index 0000000000..4ed22c92e7
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/SmfValueIdmap.html
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+-->
+<!-- SCCS keyword
+#ident "%Z%%M% %I% %E% SMI"
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Value Identity Mapping Properties is in the Authorizations Include
+column, it grants the the authorization to change Identity Mapping
+service property values.
+<P>
+If Value Identity Mapping Properties is grayed, then you are not entitled to
+Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/profiles/Makefile b/usr/src/lib/libsecdb/help/profiles/Makefile
index 256eb148f7..9609731158 100644
--- a/usr/src/lib/libsecdb/help/profiles/Makefile
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile
@@ -69,7 +69,9 @@ HTMLENTS = \
RtZFSFileSysMngmnt.html \
RtZFSStorageMngmnt.html \
RtZoneMngmnt.html \
- RtDefault.html
+ RtDefault.html \
+ RtIdmapMngmnt.html \
+ RtIdmapNameRulesMngmnt.html
HELPDIR = $(ROOT)/usr/lib/help
diff --git a/usr/src/lib/libsecdb/help/profiles/RtIdmapMngmnt.html b/usr/src/lib/libsecdb/help/profiles/RtIdmapMngmnt.html
new file mode 100644
index 0000000000..2990cd2328
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/profiles/RtIdmapMngmnt.html
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+-->
+<HEAD>
+ <TITLE> </TITLE>
+
+
+</HEAD>
+<BODY>
+<!-- ident "%Z%%M% %I% %E% SMI" -->
+
+When Idmap Service Management is in the Rights Included column, it grants
+the right to administer Identity Mapping service.
+<p>
+If Idmap Service Management is grayed, then you are not entitled to Add or
+Remove this right.
+<p>
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/profiles/RtIdmapNameRulesMngmnt.html b/usr/src/lib/libsecdb/help/profiles/RtIdmapNameRulesMngmnt.html
new file mode 100644
index 0000000000..57d735be1d
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/profiles/RtIdmapNameRulesMngmnt.html
@@ -0,0 +1,41 @@
+<HTML>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+-->
+<HEAD>
+ <TITLE> </TITLE>
+
+
+</HEAD>
+<BODY>
+<!-- ident "%Z%%M% %I% %E% SMI" -->
+
+When Idmap Name Mapping Management is in the Rights Included column, it
+grants the right to add and remove name-based mapping rules of Identity
+Mapping service.
+<p>
+If Idmap Name Mapping Management is grayed, then you are not entitled to Add
+or Remove this right.
+<p>
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt
index aa4b0aa45a..e4832e130c 100644
--- a/usr/src/lib/libsecdb/prof_attr.txt
+++ b/usr/src/lib/libsecdb/prof_attr.txt
@@ -57,6 +57,8 @@ Network Link Security:::Manage network link security:auths=solaris.network.link.
Network IPsec Management:::Manage IPsec and IKE:auths=solaris.smf.manage.ipsec,solaris.smf.value.ipsec;help=RtNetIPsec.html
Name Service Management:::Non-security name service scripts/commands:help=RtNameServiceAdmin.html
Name Service Security:::Security related name service scripts/commands:help=RtNameServiceSecure.html
+Idmap Service Management:::Manage Identity Mapping Service:auths=solaris.smf.manage.idmap,solaris.smf.value.idmap;help=RtIdmapMngmnt.html
+Idmap Name Mapping Management:::Manage Name-based Mapping Rules of Identity Mapping Service:auths=solaris.admin.idmap.rules;help=RtIdmapNameRulesMngmnt.html
Object Access Management:::Change ownership and permission on files:help=RtObAccessMngmnt.html
Process Management:::Manage current processes and processors:auths=solaris.smf.manage.cron,solaris.smf.manage.power;help=RtProcManagement.html
Rights Delegation:::Delegate ability to assign rights to users and roles:auths=solaris.role.delegate,solaris.profmgr.delegate,solaris.grant;help=RtRightsDelegate.html
diff --git a/usr/src/lib/libsqlite/Makefile b/usr/src/lib/libsqlite/Makefile
new file mode 100644
index 0000000000..241e3904bd
--- /dev/null
+++ b/usr/src/lib/libsqlite/Makefile
@@ -0,0 +1,64 @@
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+SUBDIRS = $(MACH)
+
+SQLITE_VERSION = 2.8.15-repcached
+
+VERS = .1
+
+include $(SRC)/lib/Makefile.lib
+
+ENCODING = ISO8859
+
+SRCDIR= src
+
+HDRS= sqlite.h sqlite-misc.h
+ROOTHDRDIR= $(ROOT)/usr/include/sqlite
+ROOTHDRS= $(HDRS:%=$(ROOTHDRDIR)/%)
+CHECKHDRS= $(HDRS:%.h=%.check)
+CLEANFILES += sqlite.h
+
+.KEEP_STATE:
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+
+# This is the default Makefile target. The objects listed here
+# are what get build when you type just "make" with no arguments.
+#
+all clobber install lint: $(SUBDIRS)
+
+$(ROOTHDRDIR):
+ $(INS.dir)
+
+$(ROOTHDRDIR)/%: % $(ROOTHDRDIR)
+ $(INS.file)
+
+install_h: sqlite.h $(ROOTHDRS)
+
+check:
+
+#
+# we don't want this output different every time, so we just suppress it
+#
+sqlite.h: $(SRCDIR)/sqlite.h.in
+ @echo "Generating $@"; \
+ sed -e 's"--VERS--"$(SQLITE_VERSION)-$(VERSION)"' \
+ -e s/--ENCODING--/$(ENCODING)/ \
+ $(SRCDIR)/sqlite.h.in > $@
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/cmd/svc/configd/sqlite/Makefile b/usr/src/lib/libsqlite/Makefile.com
index b527f74dab..49b42f553b 100644
--- a/usr/src/cmd/svc/configd/sqlite/Makefile
+++ b/usr/src/lib/libsqlite/Makefile.com
@@ -46,8 +46,8 @@ OBJECTS = \
include $(SRC)/lib/Makefile.lib
-SRCDIR = src
-TOOLDIR = tool
+SRCDIR = ../src
+TOOLDIR = ../tool
LIBS = $(RELOC) $(LINTLIB)
$(LINTLIB) := SRCS = $(LINTSRC)
@@ -85,10 +85,10 @@ SRCS = \
$(SRCDIR)/where.c \
$(SRCDIR)/trigger.c
-MYCPPFLAGS = -D_REENTRANT -DTHREADSAFE=1 -DHAVE_USLEEP=1 -I. -I$(SRCDIR)
+MYCPPFLAGS = -D_REENTRANT -DTHREADSAFE=1 -DHAVE_USLEEP=1 -I. -I.. -I$(SRCDIR)
CPPFLAGS += $(MYCPPFLAGS)
-MAPFILE = mapfile-sqlite
+MAPFILE = ../mapfile-sqlite
# Header files used by all library source files.
#
@@ -99,7 +99,7 @@ HDR = \
opcodes.h \
$(SRCDIR)/os.h \
parse.h \
- sqlite.h \
+ ../sqlite.h \
$(SRCDIR)/sqliteInt.h \
$(SRCDIR)/vdbe.h \
$(SRCDIR)/vdbeInt.h
@@ -138,8 +138,8 @@ $(NATIVETARGETS) := CPPFLAGS = $(MYCPPFLAGS)
$(NATIVETARGETS) := LDFLAGS =
$(NATIVETARGETS) := LDLIBS = -lc
-$(OBJS) shell.o := CFLAGS += $(CTF_FLAGS)
-$(OBJS) shell.o := CTFCONVERT_POST = $(CTFCONVERT_O)
+$(OBJS) := CFLAGS += $(CTF_FLAGS)
+$(OBJS) := CTFCONVERT_POST = $(CTFCONVERT_O)
TCLBASE = /usr/sfw
TCLVERS = tcl8.3
@@ -169,30 +169,28 @@ CLEANFILES += \
parse_tmp.out \
parse_tmp.y \
parse.c \
- parse.h \
- shell.o \
- sqlite \
- sqlite.h
+ parse.h
ENCODING = ISO8859
-.PARALLEL: $(OBJS) $(OBJS:%.o=%-native.o)
-.KEEP_STATE:
+LINTSRC= ../llib-lsqlite
-SQLITE = sqlite
-ROOTLIBSVCBIN = $(ROOT)/lib/svc/bin
-ROOTSQLITE = $(ROOTLIBSVCBIN)/$(SQLITE)
+.PARALLEL: $(OBJS) $(OBJS:%.o=%-native.o)
+.KEEP_STATE:
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
-all: $(LIBS) $(SQLITE)
-install: all $(ROOTSQLITE)
+all: $(LIBS)
+install: all $(ROOTLIBDIR)/$(RELOC) $(ROOTLIBDIR)/$(NATIVERELOC) \
+ $(ROOTLIBDIR)/llib-lsqlite.ln
-$(ROOTSQLITE) := FILEMODE = 555
+$(ROOTLIBDIR)/$(RELOC) := FILEMODE= 644
+$(ROOTLIBDIR)/$(NATIVERELOC) := FILEMODE= 644
+$(ROOTLIBDIR)/llib-lsqlite.ln := FILEMODE= 644
-$(ROOTLIBSVCBIN)/%: %
+$(ROOTLIBDIR)/%: %
$(INS.file)
$(OBJS) $(OBJS:%.o=%-native.o): $(HDR)
@@ -206,15 +204,6 @@ $(RELOC): objs .WAIT $(OBJS)
$(NATIVERELOC): objs .WAIT $(OBJS:%.o=%-native.o)
$(LD) -r $(MAPFILE:%=-M%) -o $(NATIVERELOC) $(OBJS:%.o=%-native.o)
-#
-# we don't want this output different every time, so we just suppress it
-#
-sqlite.h: $(SRCDIR)/sqlite.h.in
- @echo "Generating $@"; \
- sed -e 's"--VERS--"$(SQLITE_VERSION)-$(VERSION)"' \
- -e s/--ENCODING--/$(ENCODING)/ \
- $(SRCDIR)/sqlite.h.in > $@
-
opcodes.h: $(SRCDIR)/vdbe.c
@echo "Generating $@"; \
$(RM) -f $@ ; \
@@ -246,14 +235,6 @@ lemon-build: lemon.o $(TOOLDIR)/lempar.c
$(RM) lemon-build
$(CP) lemon lemon-build
-shell.o: sqlite.h
-
-sqlite: shell.o $(RELOC)
- $(LINK.c) -o sqlite shell.o \
- $(MAPFILE.NES:%=-M%) $(MAPFILE.NED:%=-M%) $(RELOC)
- $(CTFMERGE) -t -L VERSION -o $@ shell.o $(RELOC)
- $(POST_PROCESS)
-
testfixture: FRC
@if [ -f $(TCLBASE)/include/tcl.h ]; then \
unset SUNPRO_DEPENDENCIES; \
diff --git a/usr/src/lib/libsqlite/i386/Makefile b/usr/src/lib/libsqlite/i386/Makefile
new file mode 100644
index 0000000000..1cdf2c61ae
--- /dev/null
+++ b/usr/src/lib/libsqlite/i386/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBDIR)/$(RELOC)
+
+$(ROOTLIBDIR)/$(RELOC): all
diff --git a/usr/src/cmd/svc/configd/sqlite/inc.flg b/usr/src/lib/libsqlite/inc.flg
index 7c0ea43c86..7c0ea43c86 100644
--- a/usr/src/cmd/svc/configd/sqlite/inc.flg
+++ b/usr/src/lib/libsqlite/inc.flg
diff --git a/usr/src/cmd/svc/configd/sqlite/llib-lsqlite b/usr/src/lib/libsqlite/llib-lsqlite
index 220ae71518..220ae71518 100644
--- a/usr/src/cmd/svc/configd/sqlite/llib-lsqlite
+++ b/usr/src/lib/libsqlite/llib-lsqlite
diff --git a/usr/src/cmd/svc/configd/sqlite/main.mk b/usr/src/lib/libsqlite/main.mk
index ebcb86b2ee..ebcb86b2ee 100644
--- a/usr/src/cmd/svc/configd/sqlite/main.mk
+++ b/usr/src/lib/libsqlite/main.mk
diff --git a/usr/src/cmd/svc/configd/sqlite/mapfile-sqlite b/usr/src/lib/libsqlite/mapfile-sqlite
index 43c22f5823..43c22f5823 100644
--- a/usr/src/cmd/svc/configd/sqlite/mapfile-sqlite
+++ b/usr/src/lib/libsqlite/mapfile-sqlite
diff --git a/usr/src/lib/libsqlite/sparc/Makefile b/usr/src/lib/libsqlite/sparc/Makefile
new file mode 100644
index 0000000000..1cdf2c61ae
--- /dev/null
+++ b/usr/src/lib/libsqlite/sparc/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: $(ROOTLIBDIR)/$(RELOC)
+
+$(ROOTLIBDIR)/$(RELOC): all
diff --git a/usr/src/cmd/svc/configd/sqlite/sqlite-misc.h b/usr/src/lib/libsqlite/sqlite-misc.h
index d2d2745ba0..d2d2745ba0 100644
--- a/usr/src/cmd/svc/configd/sqlite/sqlite-misc.h
+++ b/usr/src/lib/libsqlite/sqlite-misc.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/attach.c b/usr/src/lib/libsqlite/src/attach.c
index c3e9ca3c1c..c3e9ca3c1c 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/attach.c
+++ b/usr/src/lib/libsqlite/src/attach.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/auth.c b/usr/src/lib/libsqlite/src/auth.c
index 0fb7a47658..0fb7a47658 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/auth.c
+++ b/usr/src/lib/libsqlite/src/auth.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/btree.c b/usr/src/lib/libsqlite/src/btree.c
index f4b47fa6f9..f4b47fa6f9 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/btree.c
+++ b/usr/src/lib/libsqlite/src/btree.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/btree.h b/usr/src/lib/libsqlite/src/btree.h
index cfb5efc31d..cfb5efc31d 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/btree.h
+++ b/usr/src/lib/libsqlite/src/btree.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/btree_rb.c b/usr/src/lib/libsqlite/src/btree_rb.c
index 71b1334e2c..71b1334e2c 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/btree_rb.c
+++ b/usr/src/lib/libsqlite/src/btree_rb.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/build.c b/usr/src/lib/libsqlite/src/build.c
index 4de92ef15b..4de92ef15b 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/build.c
+++ b/usr/src/lib/libsqlite/src/build.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/config.h b/usr/src/lib/libsqlite/src/config.h
index 9310f9188e..9310f9188e 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/config.h
+++ b/usr/src/lib/libsqlite/src/config.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/copy.c b/usr/src/lib/libsqlite/src/copy.c
index 811946b5a3..811946b5a3 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/copy.c
+++ b/usr/src/lib/libsqlite/src/copy.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/date.c b/usr/src/lib/libsqlite/src/date.c
index 4c7db47449..4c7db47449 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/date.c
+++ b/usr/src/lib/libsqlite/src/date.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/delete.c b/usr/src/lib/libsqlite/src/delete.c
index 949e4c2baa..949e4c2baa 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/delete.c
+++ b/usr/src/lib/libsqlite/src/delete.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/encode.c b/usr/src/lib/libsqlite/src/encode.c
index 9d48ec9e42..9d48ec9e42 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/encode.c
+++ b/usr/src/lib/libsqlite/src/encode.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/expr.c b/usr/src/lib/libsqlite/src/expr.c
index 1155d045f6..1155d045f6 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/expr.c
+++ b/usr/src/lib/libsqlite/src/expr.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/func.c b/usr/src/lib/libsqlite/src/func.c
index 6c3915f7a8..6c3915f7a8 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/func.c
+++ b/usr/src/lib/libsqlite/src/func.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/hash.c b/usr/src/lib/libsqlite/src/hash.c
index fba18bb33b..fba18bb33b 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/hash.c
+++ b/usr/src/lib/libsqlite/src/hash.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/hash.h b/usr/src/lib/libsqlite/src/hash.h
index 89671655c2..89671655c2 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/hash.h
+++ b/usr/src/lib/libsqlite/src/hash.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/insert.c b/usr/src/lib/libsqlite/src/insert.c
index 334acbf941..334acbf941 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/insert.c
+++ b/usr/src/lib/libsqlite/src/insert.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/main.c b/usr/src/lib/libsqlite/src/main.c
index 41e7afa4dc..41e7afa4dc 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/main.c
+++ b/usr/src/lib/libsqlite/src/main.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/md5.c b/usr/src/lib/libsqlite/src/md5.c
index 5b61b5eb34..5b61b5eb34 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/md5.c
+++ b/usr/src/lib/libsqlite/src/md5.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/os.c b/usr/src/lib/libsqlite/src/os.c
index 93af251869..93af251869 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/os.c
+++ b/usr/src/lib/libsqlite/src/os.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/os.h b/usr/src/lib/libsqlite/src/os.h
index e50e3d713b..e50e3d713b 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/os.h
+++ b/usr/src/lib/libsqlite/src/os.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/pager.c b/usr/src/lib/libsqlite/src/pager.c
index 276dd0ae42..276dd0ae42 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/pager.c
+++ b/usr/src/lib/libsqlite/src/pager.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/pager.h b/usr/src/lib/libsqlite/src/pager.h
index 7c22b950c1..7c22b950c1 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/pager.h
+++ b/usr/src/lib/libsqlite/src/pager.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/parse.y b/usr/src/lib/libsqlite/src/parse.y
index c3122e7280..c3122e7280 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/parse.y
+++ b/usr/src/lib/libsqlite/src/parse.y
diff --git a/usr/src/cmd/svc/configd/sqlite/src/pragma.c b/usr/src/lib/libsqlite/src/pragma.c
index 2a944c2628..2a944c2628 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/pragma.c
+++ b/usr/src/lib/libsqlite/src/pragma.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/printf.c b/usr/src/lib/libsqlite/src/printf.c
index 27bd2ac758..27bd2ac758 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/printf.c
+++ b/usr/src/lib/libsqlite/src/printf.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/random.c b/usr/src/lib/libsqlite/src/random.c
index e0fac930a6..e0fac930a6 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/random.c
+++ b/usr/src/lib/libsqlite/src/random.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/select.c b/usr/src/lib/libsqlite/src/select.c
index 92acc32c98..92acc32c98 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/select.c
+++ b/usr/src/lib/libsqlite/src/select.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/sqlite.h.in b/usr/src/lib/libsqlite/src/sqlite.h.in
index d7ab189b43..d7ab189b43 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/sqlite.h.in
+++ b/usr/src/lib/libsqlite/src/sqlite.h.in
diff --git a/usr/src/cmd/svc/configd/sqlite/src/sqliteInt.h b/usr/src/lib/libsqlite/src/sqliteInt.h
index 046f008356..046f008356 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/sqliteInt.h
+++ b/usr/src/lib/libsqlite/src/sqliteInt.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/table.c b/usr/src/lib/libsqlite/src/table.c
index 1cbbcb3b14..1cbbcb3b14 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/table.c
+++ b/usr/src/lib/libsqlite/src/table.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/tclsqlite.c b/usr/src/lib/libsqlite/src/tclsqlite.c
index 85d2029b53..85d2029b53 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/tclsqlite.c
+++ b/usr/src/lib/libsqlite/src/tclsqlite.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/test1.c b/usr/src/lib/libsqlite/src/test1.c
index 6434d90500..6434d90500 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/test1.c
+++ b/usr/src/lib/libsqlite/src/test1.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/test2.c b/usr/src/lib/libsqlite/src/test2.c
index 2d85769d05..2d85769d05 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/test2.c
+++ b/usr/src/lib/libsqlite/src/test2.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/test3.c b/usr/src/lib/libsqlite/src/test3.c
index 8b3fb8e507..8b3fb8e507 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/test3.c
+++ b/usr/src/lib/libsqlite/src/test3.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/test4.c b/usr/src/lib/libsqlite/src/test4.c
index 966ae6c9b1..966ae6c9b1 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/test4.c
+++ b/usr/src/lib/libsqlite/src/test4.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/tokenize.c b/usr/src/lib/libsqlite/src/tokenize.c
index c7a6da42cb..c7a6da42cb 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/tokenize.c
+++ b/usr/src/lib/libsqlite/src/tokenize.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/trigger.c b/usr/src/lib/libsqlite/src/trigger.c
index 1370f91d2e..1370f91d2e 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/trigger.c
+++ b/usr/src/lib/libsqlite/src/trigger.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/update.c b/usr/src/lib/libsqlite/src/update.c
index d90b144f2a..d90b144f2a 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/update.c
+++ b/usr/src/lib/libsqlite/src/update.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/util.c b/usr/src/lib/libsqlite/src/util.c
index 8dda556f18..8dda556f18 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/util.c
+++ b/usr/src/lib/libsqlite/src/util.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/vacuum.c b/usr/src/lib/libsqlite/src/vacuum.c
index ba425a7916..ba425a7916 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/vacuum.c
+++ b/usr/src/lib/libsqlite/src/vacuum.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/vdbe.c b/usr/src/lib/libsqlite/src/vdbe.c
index d631a98543..d631a98543 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/vdbe.c
+++ b/usr/src/lib/libsqlite/src/vdbe.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/vdbe.h b/usr/src/lib/libsqlite/src/vdbe.h
index c95a69e0e7..c95a69e0e7 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/vdbe.h
+++ b/usr/src/lib/libsqlite/src/vdbe.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/vdbeInt.h b/usr/src/lib/libsqlite/src/vdbeInt.h
index 0d16eb23e8..0d16eb23e8 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/vdbeInt.h
+++ b/usr/src/lib/libsqlite/src/vdbeInt.h
diff --git a/usr/src/cmd/svc/configd/sqlite/src/vdbeaux.c b/usr/src/lib/libsqlite/src/vdbeaux.c
index aea32dd8f8..aea32dd8f8 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/vdbeaux.c
+++ b/usr/src/lib/libsqlite/src/vdbeaux.c
diff --git a/usr/src/cmd/svc/configd/sqlite/src/where.c b/usr/src/lib/libsqlite/src/where.c
index dd2affec73..dd2affec73 100644
--- a/usr/src/cmd/svc/configd/sqlite/src/where.c
+++ b/usr/src/lib/libsqlite/src/where.c
diff --git a/usr/src/cmd/svc/configd/sqlite/test/all.test b/usr/src/lib/libsqlite/test/all.test
index 2cdd89c2bf..2cdd89c2bf 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/all.test
+++ b/usr/src/lib/libsqlite/test/all.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/attach.test b/usr/src/lib/libsqlite/test/attach.test
index 67521eaa85..67521eaa85 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/attach.test
+++ b/usr/src/lib/libsqlite/test/attach.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/attach2.test b/usr/src/lib/libsqlite/test/attach2.test
index 2ed427205a..2ed427205a 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/attach2.test
+++ b/usr/src/lib/libsqlite/test/attach2.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/auth.test b/usr/src/lib/libsqlite/test/auth.test
index 1719ec7ad1..1719ec7ad1 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/auth.test
+++ b/usr/src/lib/libsqlite/test/auth.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/bigfile.test b/usr/src/lib/libsqlite/test/bigfile.test
index d3d0d21fb9..d3d0d21fb9 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/bigfile.test
+++ b/usr/src/lib/libsqlite/test/bigfile.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/bigrow.test b/usr/src/lib/libsqlite/test/bigrow.test
index b9aed8e7e1..b9aed8e7e1 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/bigrow.test
+++ b/usr/src/lib/libsqlite/test/bigrow.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/bind.test b/usr/src/lib/libsqlite/test/bind.test
index 0f87255666..0f87255666 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/bind.test
+++ b/usr/src/lib/libsqlite/test/bind.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/btree.test b/usr/src/lib/libsqlite/test/btree.test
index 9d1c4153d7..9d1c4153d7 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/btree.test
+++ b/usr/src/lib/libsqlite/test/btree.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/btree2.test b/usr/src/lib/libsqlite/test/btree2.test
index 45c0203a52..45c0203a52 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/btree2.test
+++ b/usr/src/lib/libsqlite/test/btree2.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/btree3.test b/usr/src/lib/libsqlite/test/btree3.test
index 784759f176..784759f176 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/btree3.test
+++ b/usr/src/lib/libsqlite/test/btree3.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/btree3rb.test b/usr/src/lib/libsqlite/test/btree3rb.test
index ab249a6ca0..ab249a6ca0 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/btree3rb.test
+++ b/usr/src/lib/libsqlite/test/btree3rb.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/btree4.test b/usr/src/lib/libsqlite/test/btree4.test
index b18790388a..b18790388a 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/btree4.test
+++ b/usr/src/lib/libsqlite/test/btree4.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/btree4rb.test b/usr/src/lib/libsqlite/test/btree4rb.test
index 3be7f1edbc..3be7f1edbc 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/btree4rb.test
+++ b/usr/src/lib/libsqlite/test/btree4rb.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/capi2.test b/usr/src/lib/libsqlite/test/capi2.test
index 1bb32628a9..1bb32628a9 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/capi2.test
+++ b/usr/src/lib/libsqlite/test/capi2.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/conflict.test b/usr/src/lib/libsqlite/test/conflict.test
index dfb1c88f42..dfb1c88f42 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/conflict.test
+++ b/usr/src/lib/libsqlite/test/conflict.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/copy.test b/usr/src/lib/libsqlite/test/copy.test
index 68fa7f8fd2..68fa7f8fd2 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/copy.test
+++ b/usr/src/lib/libsqlite/test/copy.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/crashme2.off b/usr/src/lib/libsqlite/test/crashme2.off
index a6a4e77353..a6a4e77353 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/crashme2.off
+++ b/usr/src/lib/libsqlite/test/crashme2.off
diff --git a/usr/src/cmd/svc/configd/sqlite/test/crashtest1.c b/usr/src/lib/libsqlite/test/crashtest1.c
index ed82867dd8..ed82867dd8 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/crashtest1.c
+++ b/usr/src/lib/libsqlite/test/crashtest1.c
diff --git a/usr/src/cmd/svc/configd/sqlite/test/date.test b/usr/src/lib/libsqlite/test/date.test
index b145e3cadd..b145e3cadd 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/date.test
+++ b/usr/src/lib/libsqlite/test/date.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/delete.test b/usr/src/lib/libsqlite/test/delete.test
index 1676323507..1676323507 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/delete.test
+++ b/usr/src/lib/libsqlite/test/delete.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/expr.test b/usr/src/lib/libsqlite/test/expr.test
index 2f4fb26924..2f4fb26924 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/expr.test
+++ b/usr/src/lib/libsqlite/test/expr.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/fkey1.test b/usr/src/lib/libsqlite/test/fkey1.test
index 4e0b4d6400..4e0b4d6400 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/fkey1.test
+++ b/usr/src/lib/libsqlite/test/fkey1.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/format3.test b/usr/src/lib/libsqlite/test/format3.test
index bcad7d957e..bcad7d957e 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/format3.test
+++ b/usr/src/lib/libsqlite/test/format3.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/func.test b/usr/src/lib/libsqlite/test/func.test
index 521e6af45f..521e6af45f 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/func.test
+++ b/usr/src/lib/libsqlite/test/func.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/hook.test b/usr/src/lib/libsqlite/test/hook.test
index dd8ebf3573..dd8ebf3573 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/hook.test
+++ b/usr/src/lib/libsqlite/test/hook.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/in.test b/usr/src/lib/libsqlite/test/in.test
index 612dc1909c..612dc1909c 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/in.test
+++ b/usr/src/lib/libsqlite/test/in.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/index.test b/usr/src/lib/libsqlite/test/index.test
index aabe7f3869..aabe7f3869 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/index.test
+++ b/usr/src/lib/libsqlite/test/index.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/insert.test b/usr/src/lib/libsqlite/test/insert.test
index b615347712..b615347712 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/insert.test
+++ b/usr/src/lib/libsqlite/test/insert.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/insert2.test b/usr/src/lib/libsqlite/test/insert2.test
index 1d1d72a11a..1d1d72a11a 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/insert2.test
+++ b/usr/src/lib/libsqlite/test/insert2.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/interrupt.test b/usr/src/lib/libsqlite/test/interrupt.test
index d98ff2ae7e..d98ff2ae7e 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/interrupt.test
+++ b/usr/src/lib/libsqlite/test/interrupt.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/intpkey.test b/usr/src/lib/libsqlite/test/intpkey.test
index 546ab8649a..546ab8649a 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/intpkey.test
+++ b/usr/src/lib/libsqlite/test/intpkey.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/ioerr.test b/usr/src/lib/libsqlite/test/ioerr.test
index d7539bc209..d7539bc209 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/ioerr.test
+++ b/usr/src/lib/libsqlite/test/ioerr.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/join.test b/usr/src/lib/libsqlite/test/join.test
index 990a623e54..990a623e54 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/join.test
+++ b/usr/src/lib/libsqlite/test/join.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/join2.test b/usr/src/lib/libsqlite/test/join2.test
index 493e1a8613..493e1a8613 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/join2.test
+++ b/usr/src/lib/libsqlite/test/join2.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/join3_28.test b/usr/src/lib/libsqlite/test/join3_28.test
index 5ddbb8a1d5..5ddbb8a1d5 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/join3_28.test
+++ b/usr/src/lib/libsqlite/test/join3_28.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/join4_28.test b/usr/src/lib/libsqlite/test/join4_28.test
index 189a44af32..189a44af32 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/join4_28.test
+++ b/usr/src/lib/libsqlite/test/join4_28.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/lastinsert.test b/usr/src/lib/libsqlite/test/lastinsert.test
index 8137d1763b..8137d1763b 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/lastinsert.test
+++ b/usr/src/lib/libsqlite/test/lastinsert.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/laststmtchanges.test b/usr/src/lib/libsqlite/test/laststmtchanges.test
index b35ed12731..b35ed12731 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/laststmtchanges.test
+++ b/usr/src/lib/libsqlite/test/laststmtchanges.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/limit.test b/usr/src/lib/libsqlite/test/limit.test
index 04a56fe798..04a56fe798 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/limit.test
+++ b/usr/src/lib/libsqlite/test/limit.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/lock.test b/usr/src/lib/libsqlite/test/lock.test
index ca4310c4b2..ca4310c4b2 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/lock.test
+++ b/usr/src/lib/libsqlite/test/lock.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/main.test b/usr/src/lib/libsqlite/test/main.test
index 529e40ed61..529e40ed61 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/main.test
+++ b/usr/src/lib/libsqlite/test/main.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/malloc.test b/usr/src/lib/libsqlite/test/malloc.test
index 613435d28a..613435d28a 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/malloc.test
+++ b/usr/src/lib/libsqlite/test/malloc.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/memdb.test b/usr/src/lib/libsqlite/test/memdb.test
index c70d60c4d3..c70d60c4d3 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/memdb.test
+++ b/usr/src/lib/libsqlite/test/memdb.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/memleak.test b/usr/src/lib/libsqlite/test/memleak.test
index 96c7783481..96c7783481 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/memleak.test
+++ b/usr/src/lib/libsqlite/test/memleak.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/minmax.test b/usr/src/lib/libsqlite/test/minmax.test
index 8235983f0d..8235983f0d 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/minmax.test
+++ b/usr/src/lib/libsqlite/test/minmax.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/misc1.test b/usr/src/lib/libsqlite/test/misc1.test
index 9e75a087b2..9e75a087b2 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/misc1.test
+++ b/usr/src/lib/libsqlite/test/misc1.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/misc2.test b/usr/src/lib/libsqlite/test/misc2.test
index 23ddc3dfef..23ddc3dfef 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/misc2.test
+++ b/usr/src/lib/libsqlite/test/misc2.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/misc3.test b/usr/src/lib/libsqlite/test/misc3.test
index a91da5feb9..a91da5feb9 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/misc3.test
+++ b/usr/src/lib/libsqlite/test/misc3.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/misuse.test b/usr/src/lib/libsqlite/test/misuse.test
index f4d15be304..f4d15be304 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/misuse.test
+++ b/usr/src/lib/libsqlite/test/misuse.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/notnull.test b/usr/src/lib/libsqlite/test/notnull.test
index cd2691a084..cd2691a084 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/notnull.test
+++ b/usr/src/lib/libsqlite/test/notnull.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/null.test b/usr/src/lib/libsqlite/test/null.test
index 6c816d8584..6c816d8584 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/null.test
+++ b/usr/src/lib/libsqlite/test/null.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/pager.test b/usr/src/lib/libsqlite/test/pager.test
index 3f68719e34..3f68719e34 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/pager.test
+++ b/usr/src/lib/libsqlite/test/pager.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/pragma.test b/usr/src/lib/libsqlite/test/pragma.test
index f7cf3fa6a3..f7cf3fa6a3 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/pragma.test
+++ b/usr/src/lib/libsqlite/test/pragma.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/printf.test b/usr/src/lib/libsqlite/test/printf.test
index a0adc72435..a0adc72435 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/printf.test
+++ b/usr/src/lib/libsqlite/test/printf.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/progress.test b/usr/src/lib/libsqlite/test/progress.test
index 4d94239a04..4d94239a04 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/progress.test
+++ b/usr/src/lib/libsqlite/test/progress.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/quick.test b/usr/src/lib/libsqlite/test/quick.test
index 5faf95a466..5faf95a466 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/quick.test
+++ b/usr/src/lib/libsqlite/test/quick.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/quote.test b/usr/src/lib/libsqlite/test/quote.test
index 5fb9e85736..5fb9e85736 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/quote.test
+++ b/usr/src/lib/libsqlite/test/quote.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/rowid.test b/usr/src/lib/libsqlite/test/rowid.test
index 7cb5dc57c8..7cb5dc57c8 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/rowid.test
+++ b/usr/src/lib/libsqlite/test/rowid.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/select1.test b/usr/src/lib/libsqlite/test/select1.test
index 0d770adec7..0d770adec7 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/select1.test
+++ b/usr/src/lib/libsqlite/test/select1.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/select2.test b/usr/src/lib/libsqlite/test/select2.test
index 446f1b3e7b..446f1b3e7b 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/select2.test
+++ b/usr/src/lib/libsqlite/test/select2.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/select3.test b/usr/src/lib/libsqlite/test/select3.test
index c7a232d076..c7a232d076 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/select3.test
+++ b/usr/src/lib/libsqlite/test/select3.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/select4.test b/usr/src/lib/libsqlite/test/select4.test
index 8fb34a2156..8fb34a2156 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/select4.test
+++ b/usr/src/lib/libsqlite/test/select4.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/select5.test b/usr/src/lib/libsqlite/test/select5.test
index 7db30d07db..7db30d07db 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/select5.test
+++ b/usr/src/lib/libsqlite/test/select5.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/select6.test b/usr/src/lib/libsqlite/test/select6.test
index 13ff398e98..13ff398e98 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/select6.test
+++ b/usr/src/lib/libsqlite/test/select6.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/sort.test b/usr/src/lib/libsqlite/test/sort.test
index 337b15d609..337b15d609 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/sort.test
+++ b/usr/src/lib/libsqlite/test/sort.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/subselect.test b/usr/src/lib/libsqlite/test/subselect.test
index 85b3911935..85b3911935 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/subselect.test
+++ b/usr/src/lib/libsqlite/test/subselect.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/table.test b/usr/src/lib/libsqlite/test/table.test
index f04b2a5bad..f04b2a5bad 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/table.test
+++ b/usr/src/lib/libsqlite/test/table.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/tableapi.test b/usr/src/lib/libsqlite/test/tableapi.test
index a41fd55695..a41fd55695 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/tableapi.test
+++ b/usr/src/lib/libsqlite/test/tableapi.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/tclsqlite.test b/usr/src/lib/libsqlite/test/tclsqlite.test
index d5a4249c7f..d5a4249c7f 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/tclsqlite.test
+++ b/usr/src/lib/libsqlite/test/tclsqlite.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/temptable.test b/usr/src/lib/libsqlite/test/temptable.test
index 93ff24bc6c..93ff24bc6c 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/temptable.test
+++ b/usr/src/lib/libsqlite/test/temptable.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/tester.tcl b/usr/src/lib/libsqlite/test/tester.tcl
index 8cc6951eee..8cc6951eee 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/tester.tcl
+++ b/usr/src/lib/libsqlite/test/tester.tcl
diff --git a/usr/src/cmd/svc/configd/sqlite/test/thread1.test b/usr/src/lib/libsqlite/test/thread1.test
index cbca2e364a..cbca2e364a 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/thread1.test
+++ b/usr/src/lib/libsqlite/test/thread1.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/threadtest1.c b/usr/src/lib/libsqlite/test/threadtest1.c
index 48f4bf7679..48f4bf7679 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/threadtest1.c
+++ b/usr/src/lib/libsqlite/test/threadtest1.c
diff --git a/usr/src/cmd/svc/configd/sqlite/test/threadtest2.c b/usr/src/lib/libsqlite/test/threadtest2.c
index 9e49e50af1..9e49e50af1 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/threadtest2.c
+++ b/usr/src/lib/libsqlite/test/threadtest2.c
diff --git a/usr/src/cmd/svc/configd/sqlite/test/trans.test b/usr/src/lib/libsqlite/test/trans.test
index a6b27e4953..a6b27e4953 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/trans.test
+++ b/usr/src/lib/libsqlite/test/trans.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/trigger1.test b/usr/src/lib/libsqlite/test/trigger1.test
index 44e1091597..44e1091597 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/trigger1.test
+++ b/usr/src/lib/libsqlite/test/trigger1.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/trigger2.test b/usr/src/lib/libsqlite/test/trigger2.test
index 7567f01fcd..7567f01fcd 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/trigger2.test
+++ b/usr/src/lib/libsqlite/test/trigger2.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/trigger3.test b/usr/src/lib/libsqlite/test/trigger3.test
index bf4101600b..bf4101600b 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/trigger3.test
+++ b/usr/src/lib/libsqlite/test/trigger3.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/trigger4.test b/usr/src/lib/libsqlite/test/trigger4.test
index 9f6301bee1..9f6301bee1 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/trigger4.test
+++ b/usr/src/lib/libsqlite/test/trigger4.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/unique.test b/usr/src/lib/libsqlite/test/unique.test
index 9b6977bf71..9b6977bf71 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/unique.test
+++ b/usr/src/lib/libsqlite/test/unique.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/update.test b/usr/src/lib/libsqlite/test/update.test
index 48e270f704..48e270f704 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/update.test
+++ b/usr/src/lib/libsqlite/test/update.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/vacuum.test b/usr/src/lib/libsqlite/test/vacuum.test
index 4154107c97..4154107c97 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/vacuum.test
+++ b/usr/src/lib/libsqlite/test/vacuum.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/version.test b/usr/src/lib/libsqlite/test/version.test
index 2e44e0b6ab..2e44e0b6ab 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/version.test
+++ b/usr/src/lib/libsqlite/test/version.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/view.test b/usr/src/lib/libsqlite/test/view.test
index 2da7e8deb6..2da7e8deb6 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/view.test
+++ b/usr/src/lib/libsqlite/test/view.test
diff --git a/usr/src/cmd/svc/configd/sqlite/test/where.test b/usr/src/lib/libsqlite/test/where.test
index 5671de9b7d..5671de9b7d 100644
--- a/usr/src/cmd/svc/configd/sqlite/test/where.test
+++ b/usr/src/lib/libsqlite/test/where.test
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/diffdb.c b/usr/src/lib/libsqlite/tool/diffdb.c
index 8b94871fd5..8b94871fd5 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/diffdb.c
+++ b/usr/src/lib/libsqlite/tool/diffdb.c
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/lemon.c b/usr/src/lib/libsqlite/tool/lemon.c
index d0321b0f55..d0321b0f55 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/lemon.c
+++ b/usr/src/lib/libsqlite/tool/lemon.c
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/lempar.c b/usr/src/lib/libsqlite/tool/lempar.c
index dcdf5fe31a..dcdf5fe31a 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/lempar.c
+++ b/usr/src/lib/libsqlite/tool/lempar.c
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/memleak.awk b/usr/src/lib/libsqlite/tool/memleak.awk
index fa2a22ef89..fa2a22ef89 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/memleak.awk
+++ b/usr/src/lib/libsqlite/tool/memleak.awk
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/memleak2.awk b/usr/src/lib/libsqlite/tool/memleak2.awk
index 51b3a1fa7a..51b3a1fa7a 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/memleak2.awk
+++ b/usr/src/lib/libsqlite/tool/memleak2.awk
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/mkopts.tcl b/usr/src/lib/libsqlite/tool/mkopts.tcl
index fb906f5df7..fb906f5df7 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/mkopts.tcl
+++ b/usr/src/lib/libsqlite/tool/mkopts.tcl
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/opcodeDoc.awk b/usr/src/lib/libsqlite/tool/opcodeDoc.awk
index 19f824bfac..19f824bfac 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/opcodeDoc.awk
+++ b/usr/src/lib/libsqlite/tool/opcodeDoc.awk
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/report1.txt b/usr/src/lib/libsqlite/tool/report1.txt
index d1eb9364a0..d1eb9364a0 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/report1.txt
+++ b/usr/src/lib/libsqlite/tool/report1.txt
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/showdb.c b/usr/src/lib/libsqlite/tool/showdb.c
index 6df9a73df8..6df9a73df8 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/showdb.c
+++ b/usr/src/lib/libsqlite/tool/showdb.c
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/showjournal.c b/usr/src/lib/libsqlite/tool/showjournal.c
index 61a9327ae6..61a9327ae6 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/showjournal.c
+++ b/usr/src/lib/libsqlite/tool/showjournal.c
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/space_used.tcl b/usr/src/lib/libsqlite/tool/space_used.tcl
index bbcc30b43c..bbcc30b43c 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/space_used.tcl
+++ b/usr/src/lib/libsqlite/tool/space_used.tcl
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/spaceanal.tcl b/usr/src/lib/libsqlite/tool/spaceanal.tcl
index 093a99a648..093a99a648 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/spaceanal.tcl
+++ b/usr/src/lib/libsqlite/tool/spaceanal.tcl
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/speedtest.tcl b/usr/src/lib/libsqlite/tool/speedtest.tcl
index e0ce4e91dd..e0ce4e91dd 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/speedtest.tcl
+++ b/usr/src/lib/libsqlite/tool/speedtest.tcl
diff --git a/usr/src/cmd/svc/configd/sqlite/tool/speedtest2.tcl b/usr/src/lib/libsqlite/tool/speedtest2.tcl
index fed7efb7cc..fed7efb7cc 100644
--- a/usr/src/cmd/svc/configd/sqlite/tool/speedtest2.tcl
+++ b/usr/src/lib/libsqlite/tool/speedtest2.tcl
diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com
index 3781c69871..c268e5555b 100644
--- a/usr/src/pkgdefs/SUNW0on/prototype_com
+++ b/usr/src/pkgdefs/SUNW0on/prototype_com
@@ -254,6 +254,9 @@ f none usr/lib/help/auths/locale/LinkSecurity.html 444 root bin
f none usr/lib/help/auths/locale/MailHeader.html 0444 root bin
f none usr/lib/help/auths/locale/MailQueue.html 0444 root bin
f none usr/lib/help/auths/locale/DevCDRW.html 0444 root bin
+f none usr/lib/help/auths/locale/IdmapRules.html 0444 root bin
+f none usr/lib/help/auths/locale/SmfIdmapStates.html 0444 root bin
+f none usr/lib/help/auths/locale/SmfValueIdmap.html 0444 root bin
d none usr/lib/help/profiles 755 root bin
d none usr/lib/help/profiles/locale 755 root bin
f none usr/lib/help/profiles/locale/RtAll.html 444 root bin
@@ -297,6 +300,8 @@ f none usr/lib/help/profiles/locale/RtDatAdmin.html 444 root bin
f none usr/lib/help/profiles/locale/RtZFSFileSysMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/RtZFSStorageMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/RtZoneMngmnt.html 444 root bin
+f none usr/lib/help/profiles/locale/RtIdmapMngmnt.html 444 root bin
+f none usr/lib/help/profiles/locale/RtIdmapNameRulesMngmnt.html 444 root bin
#
#
# OCF Messages
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_i386 b/usr/src/pkgdefs/SUNWckr/prototype_i386
index 428d48a488..59d52ff14a 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386
@@ -175,6 +175,7 @@ f none kernel/misc/fssnap_if 755 root sys
f none kernel/misc/gld 755 root sys
f none kernel/misc/hook 755 root sys
f none kernel/misc/hpcsvc 755 root sys
+f none kernel/misc/idmap 755 root sys
f none kernel/misc/ipc 755 root sys
f none kernel/misc/kbtrans 755 root sys
f none kernel/misc/kcf 755 root sys
@@ -363,6 +364,7 @@ f none kernel/misc/amd64/fssnap_if 755 root sys
f none kernel/misc/amd64/gld 755 root sys
f none kernel/misc/amd64/hook 755 root sys
f none kernel/misc/amd64/hpcsvc 755 root sys
+f none kernel/misc/amd64/idmap 755 root sys
f none kernel/misc/amd64/ipc 755 root sys
f none kernel/misc/amd64/kbtrans 755 root sys
f none kernel/misc/amd64/kcf 755 root sys
diff --git a/usr/src/pkgdefs/SUNWckr/prototype_sparc b/usr/src/pkgdefs/SUNWckr/prototype_sparc
index 3fc2f04bf8..fd635bf55f 100644
--- a/usr/src/pkgdefs/SUNWckr/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc
@@ -174,6 +174,7 @@ f none kernel/misc/sparcv9/fssnap_if 755 root sys
f none kernel/misc/sparcv9/gld 755 root sys
f none kernel/misc/sparcv9/hook 755 root sys
f none kernel/misc/sparcv9/hpcsvc 755 root sys
+f none kernel/misc/sparcv9/idmap 755 root sys
f none kernel/misc/sparcv9/ipc 755 root sys
f none kernel/misc/sparcv9/kbtrans 755 root sys
f none kernel/misc/sparcv9/kcf 755 root sys
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com
index 07e294caca..23be6ad3cd 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_com
@@ -135,6 +135,7 @@ f none usr/lib/libfstyp.so.1 755 root bin
s none usr/lib/libgen.so.1=../../lib/libgen.so.1
s none usr/lib/libgen.so=../../lib/libgen.so.1
s none usr/ccs/lib/libgen.so=../../../lib/libgen.so.1
+f none usr/lib/libidmap.so.1 755 root bin
f none usr/lib/libinetsvc.so.1 755 root bin
s none usr/lib/libinetutil.so.1=../../lib/libinetutil.so.1
f none usr/lib/libike.so.1 755 root bin
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386
index 87f5533647..6cc1d178da 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386
@@ -165,6 +165,7 @@ f none usr/lib/amd64/libform.so.1 755 root bin
s none usr/lib/amd64/libform.so=libform.so.1
s none usr/lib/amd64/libgen.so.1=../../../lib/amd64/libgen.so.1
s none usr/lib/amd64/libgen.so=../../../lib/amd64/libgen.so.1
+f none usr/lib/amd64/libidmap.so.1 755 root bin
s none usr/lib/amd64/libinetutil.so.1=../../../lib/amd64/libinetutil.so.1
f none usr/lib/amd64/libipmi.so.1 755 root bin
s none usr/lib/amd64/libipmi.so=./libipmi.so.1
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc
index 59fb0af956..1cfbcd9a26 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc
@@ -158,6 +158,7 @@ f none usr/lib/sparcv9/libform.so.1 755 root bin
s none usr/lib/sparcv9/libform.so=libform.so.1
s none usr/lib/sparcv9/libgen.so.1=../../../lib/sparcv9/libgen.so.1
s none usr/lib/sparcv9/libgen.so=../../../lib/sparcv9/libgen.so.1
+f none usr/lib/sparcv9/libidmap.so.1 755 root bin
s none usr/lib/sparcv9/libinetutil.so.1=../../../lib/sparcv9/libinetutil.so.1
f none usr/lib/sparcv9/libipmi.so.1 755 root bin
s none usr/lib/sparcv9/libipmi.so=libipmi.so.1
diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com
index b7f5d594bf..8b1400a7e5 100644
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com
@@ -436,6 +436,7 @@ e preserve var/adm/utmpx 644 root bin
e preserve var/adm/wtmpx 644 adm adm
d none var/audit 755 root sys
d none var/cron 755 root sys
+d none var/idmap 755 daemon daemon
d none var/inet 755 root sys
d none var/ld 755 root bin
s none var/ld/32=.
@@ -524,6 +525,7 @@ f manifest var/svc/manifest/system/coreadm.xml 0444 root sys
f manifest var/svc/manifest/system/cron.xml 0444 root sys
f manifest var/svc/manifest/system/cryptosvc.xml 0444 root sys
f manifest var/svc/manifest/system/identity.xml 0444 root sys
+f manifest var/svc/manifest/system/idmap.xml 0444 root sys
f manifest var/svc/manifest/system/keymap.xml 0444 root sys
f manifest var/svc/manifest/system/manifest-import.xml 0444 root sys
f manifest var/svc/manifest/system/name-service-cache.xml 0444 root sys
diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com
index d41f3b0cd7..1e722133a0 100644
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com
@@ -499,6 +499,9 @@ f none usr/lib/help/auths/locale/C/SysShutdown.html 444 root bin
f none usr/lib/help/auths/locale/C/WifiConfig.html 444 root bin
f none usr/lib/help/auths/locale/C/WifiWep.html 444 root bin
f none usr/lib/help/auths/locale/C/LinkSecurity.html 444 root bin
+f none usr/lib/help/auths/locale/C/IdmapRules.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfIdmapStates.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfValueIdmap.html 444 root bin
d none usr/lib/help/profiles 755 root bin
d none usr/lib/help/profiles/locale 755 root bin
d none usr/lib/help/profiles/locale/C 755 root bin
@@ -543,6 +546,8 @@ f none usr/lib/help/profiles/locale/C/RtUserSecurity.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtZFSFileSysMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtZFSStorageMngmnt.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtZoneMngmnt.html 444 root bin
+f none usr/lib/help/profiles/locale/C/RtIdmapMngmnt.html 444 root bin
+f none usr/lib/help/profiles/locale/C/RtIdmapNameRulesMngmnt.html 444 root bin
d none usr/lib/iconv 755 root bin
f none usr/lib/iconv/646da.8859.t 444 root bin
f none usr/lib/iconv/646de.8859.t 444 root bin
@@ -560,6 +565,7 @@ f none usr/lib/iconv/8859.646fr.t 444 root bin
f none usr/lib/iconv/8859.646it.t 444 root bin
f none usr/lib/iconv/8859.646sv.t 444 root bin
f none usr/lib/iconv/iconv_data 444 root bin
+f none usr/lib/idmapd 555 root bin
d none usr/lib/inet 755 root bin
f none usr/lib/inet/certdb 555 root bin
f none usr/lib/inet/certlocal 555 root bin
@@ -760,6 +766,7 @@ f none usr/sbin/groupmod 555 root sys
f none usr/sbin/grpck 555 root bin
f none usr/sbin/halt 755 root bin
s none usr/sbin/hostconfig=../../sbin/hostconfig
+f none usr/sbin/idmap 555 root bin
f none usr/sbin/if_mpadm 555 root bin
s none usr/sbin/ifconfig=../../sbin/ifconfig
f none usr/sbin/ikeadm 555 root bin
diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386
index 80a32243bb..a139abd570 100644
--- a/usr/src/pkgdefs/etc/exception_list_i386
+++ b/usr/src/pkgdefs/etc/exception_list_i386
@@ -835,3 +835,24 @@ usr/sbin/amd64/sharemgr i386
# Private/Internal u8_textprep header file. Do not ship.
#
usr/include/sys/u8_textprep_data.h i386
+#
+# libidmap is private, so the compilation links and lint libraries are
+# not delivered
+#
+usr/lib/llib-lidmap i386
+usr/lib/libidmap.so i386
+usr/lib/llib-lidmap.ln i386
+usr/lib/amd64/libidmap.so i386
+usr/lib/amd64/llib-lidmap.ln i386
+usr/include/idmap.h i386
+usr/include/sys/idmap.h i386
+usr/include/sys/kidmap.h i386
+#
+# SQLite is private, used by SMF (svc.configd) and idmapd
+#
+usr/lib/libsqlite-native.o i386
+usr/lib/libsqlite.o i386
+usr/lib/llib-lsqlite.ln i386
+usr/include/sqlite i386
+usr/include/sqlite/sqlite-misc.h i386
+usr/include/sqlite/sqlite.h i386
diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc
index d10863238e..d221e415c1 100644
--- a/usr/src/pkgdefs/etc/exception_list_sparc
+++ b/usr/src/pkgdefs/etc/exception_list_sparc
@@ -915,3 +915,24 @@ usr/lib/sparcv9/llib-lpri.ln sparc
# Private/Internal u8_textprep header file. Do not ship.
#
usr/include/sys/u8_textprep_data.h sparc
+#
+# libidmap is private, so the compilation links and lint libraries are
+# not delivered
+#
+usr/lib/llib-lidmap sparc
+usr/lib/libidmap.so sparc
+usr/lib/llib-lidmap.ln sparc
+usr/lib/sparcv9/libidmap.so sparc
+usr/lib/sparcv9/llib-lidmap.ln sparc
+usr/include/idmap.h sparc
+usr/include/sys/idmap.h sparc
+usr/include/sys/kidmap.h sparc
+#
+# SQLite is private, used by SMF (svc.configd) and idmapd
+#
+usr/lib/libsqlite-native.o sparc
+usr/lib/libsqlite.o sparc
+usr/lib/llib-lsqlite.ln sparc
+usr/include/sqlite sparc
+usr/include/sqlite/sqlite-misc.h sparc
+usr/include/sqlite/sqlite.h sparc
diff --git a/usr/src/tools/abi/etc/exceptions b/usr/src/tools/abi/etc/exceptions
index 2e0517bd77..2602d79c07 100644
--- a/usr/src/tools/abi/etc/exceptions
+++ b/usr/src/tools/abi/etc/exceptions
@@ -418,6 +418,9 @@ PSARC 2005/204: RULE W3: usr/lib/sparcv9/libraidcfg.so.1
6518277: RULE W3: usr/lib/libipmi.so.1
6518277: RULE W3: usr/lib/amd64/libipmi.so.1
6518277: RULE W3: usr/lib/sparcv9/libipmi.so.1
+PSARC 2006/315: RULE W3: usr/lib/libidmap.so.1
+PSARC 2006/315: RULE W3: usr/lib/amd64/libidmap.so.1
+PSARC 2006/315: RULE W3: usr/lib/sparcv9/libidmap.so.1
#############################################
# WARNINGs exempted from RULE W4 (See RULES section of intf_check manpage)
diff --git a/usr/src/tools/findunref/exception_list b/usr/src/tools/findunref/exception_list
index d9d75a8fd6..484a12991d 100644
--- a/usr/src/tools/findunref/exception_list
+++ b/usr/src/tools/findunref/exception_list
@@ -54,7 +54,8 @@
# Ignore everything under trees that may be resynched from outside ON.
#
./src/cmd/perl
-./src/cmd/svc/configd/sqlite
+./src/cmd/sqlite
+./src/lib/libsqlite
./src/cmd/tcpd
./src/common/openssl
./src/grub
diff --git a/usr/src/uts/Makefile b/usr/src/uts/Makefile
index d70037b885..2ebbb89a54 100644
--- a/usr/src/uts/Makefile
+++ b/usr/src/uts/Makefile
@@ -94,7 +94,7 @@ $(PMTMO_FILE) pmtmo_file: $(PATCH_MAKEUP_TABLE)
COMMON_HDRDIRS= common/des common/fs common/gssapi common/inet common/net \
common/netinet common/nfs common/rpc common/sys common/vm \
common/c2 common/pcmcia/sys common/rpcsvc common/inet/kssl \
- common/inet/nca common/inet/ipf/netinet common/ipp \
+ common/inet/nca common/inet/ipf/netinet common/ipp common/idmap \
common/sharefs
# These aren't the only headers in closed. But the other directories
@@ -118,6 +118,7 @@ all_h: FRC
@cd common/rpc; pwd; $(MAKE) $@
@cd common/rpcsvc; pwd; $(MAKE) $@
@cd common/gssapi; pwd; $(MAKE) $@
+ @cd common/idmap; pwd; $(MAKE) $@
ONC_FILES= common/io/timod.c \
common/os/sig.c \
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index f5593ec93a..e148047d34 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1042,6 +1042,11 @@ CRYPTMOD_OBJS += cryptmod.o
KB_OBJS += kbd.o keytables.o
#
+# ID mapping module
+#
+IDMAP_OBJS += idmap_mod.o idmap_kapi.o idmap_xdr.o idmap_cache.o
+
+#
# scheduling class modules
#
RT_OBJS += rt.o
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 8c85a4af56..dc5dd48663 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -345,6 +345,10 @@ $(OBJS_DIR)/%.o: $(KMECHKRB5_BASE)/profile/%.c
$(COMPILE.c) $(KGSSDFLAGS) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/idmap/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/inet/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1179,6 +1183,9 @@ $(LINTS_DIR)/%.ln: $(KMECHKRB5_BASE)/krb5/os/%.c
$(LINTS_DIR)/%.ln: $(KMECHKRB5_BASE)/mech/%.c
@($(LHEAD) $(LINT.c) $(KGSSDFLAGS) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/idmap/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/inet/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/idmap/Makefile b/usr/src/uts/common/idmap/Makefile
new file mode 100755
index 0000000000..a9598a269f
--- /dev/null
+++ b/usr/src/uts/common/idmap/Makefile
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# uts/common/idmap/Makefile
+#
+# include global definitions
+include ../../../Makefile.master
+
+IDMAP_PROT_DIR= $(SRC)/head/rpcsvc
+
+IDMAP_PROT_X= $(IDMAP_PROT_DIR)/idmap_prot.x
+DERIVED_SRCS= idmap_xdr.c
+DERIVED_HDRS= $(IDMAP_PROT_DIR)/idmap_prot.h
+DERIVED_FILES= $(DERIVED_SRCS) $(DERIVED_HDRS)
+HDRS= kidmap_priv.h
+CHECKHDRS= $(HDRS:%.h=%.check)
+
+.KEEP_STATE:
+
+.PARALLEL: $(CHECKHDRS)
+
+install_h: all_h
+
+all_h: $(DERIVED_FILES)
+
+
+idmap_xdr.c: $(IDMAP_PROT_X)
+ $(RM) $@
+ $(RPCGEN) -CMNc -o $@ $(IDMAP_PROT_X)
+
+$(IDMAP_PROT_DIR)/idmap_prot.h: $(IDMAP_PROT_X)
+ $(RM) $@
+ $(RPCGEN) -CMNh -o $@ $(IDMAP_PROT_X)
+
+check: $(CHECKHDRS)
+
+clean:
+ $(RM) $(DERIVED_FILES)
diff --git a/usr/src/uts/common/idmap/idmap_cache.c b/usr/src/uts/common/idmap/idmap_cache.c
new file mode 100644
index 0000000000..eb94403c0c
--- /dev/null
+++ b/usr/src/uts/common/idmap/idmap_cache.c
@@ -0,0 +1,474 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Windows to Solaris Identity Mapping kernel API
+ * This module provides the kernel cache.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#include <sys/types.h>
+#include <sys/avl.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/ksynch.h>
+#include <sys/cmn_err.h>
+#include <sys/kidmap.h>
+#include "idmap_prot.h"
+#include "kidmap_priv.h"
+
+
+/*
+ * External functions
+ */
+extern uintptr_t space_fetch(char *key);
+extern int space_store(char *key, uintptr_t ptr);
+
+
+/*
+ * Internal definitions and functions
+ */
+
+#define CACHE_TRIGGER_SIZE 8192
+#define CACHE_PURGE_INTERVAL (60 * 3)
+
+typedef struct sid_prefix_node {
+ avl_node_t avl_link;
+ const char *sid_prefix;
+} sid_prefix_node_t;
+
+
+typedef struct entry {
+ avl_node_t avl_link;
+ const char *sid_prefix;
+ uint32_t rid;
+ uid_t pid;
+ int is_user;
+ time_t ttl;
+} entry_t;
+
+typedef int (*avl_comp_fn)(const void*, const void*);
+
+
+struct sid_prefix_store {
+ struct avl_tree tree;
+ krwlock_t lock;
+};
+
+struct sid_prefix_store *kidmap_sid_prefix_store = NULL;
+
+
+
+static void
+kidmap_cache_purge_avl(idmap_avl_cache_t *cache);
+
+/*
+ * kidmap_strdup() copied from uts/common/fs/sockfs/nl7c.c
+ */
+static char *
+kidmap_strdup(const char *s)
+{
+ int len = strlen(s) + 1;
+ char *ret = kmem_alloc(len, KM_SLEEP);
+
+ bcopy(s, ret, len);
+ return (ret);
+}
+
+
+static int
+kidmap_compare_sid(const entry_t *entry1, const entry_t *entry2)
+{
+ int comp = entry2->rid - entry1->rid;
+
+ if (comp == 0)
+ comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
+
+ if (comp < 0)
+ comp = -1;
+ else if (comp > 0)
+ comp = 1;
+
+ return (comp);
+}
+
+
+static int
+kidmap_compare_pid(const entry_t *entry1, const entry_t *entry2)
+{
+ int comp = entry2->pid - entry1->pid;
+
+ if (comp == 0)
+ comp = entry2->is_user - entry1->is_user;
+
+ if (comp < 0)
+ comp = -1;
+ else if (comp > 0)
+ comp = 1;
+
+ return (comp);
+}
+
+
+static int
+kidmap_compare_sid_prefix(const sid_prefix_node_t *entry1,
+ const sid_prefix_node_t *entry2)
+{
+ int comp;
+
+ comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
+
+ if (comp < 0)
+ comp = -1;
+ else if (comp > 0)
+ comp = 1;
+
+ return (comp);
+}
+
+
+void
+kidmap_cache_create(idmap_cache_t *cache)
+{
+ typedef int (*comp)(const void*, const void*);
+
+ rw_init(&cache->sid.lock, NULL, RW_DRIVER, NULL);
+ avl_create(&cache->sid.tree, (avl_comp_fn)kidmap_compare_sid,
+ sizeof (entry_t), offsetof(entry_t, avl_link));
+ mutex_init(&cache->sid.mutex, NULL, MUTEX_DEFAULT, NULL);
+ cache->sid.state = CACHE_CREATED;
+ cache->sid.purge_time = 0;
+
+ rw_init(&cache->pid.lock, NULL, RW_DRIVER, NULL);
+ avl_create(&cache->pid.tree, (avl_comp_fn)kidmap_compare_pid,
+ sizeof (entry_t), offsetof(entry_t, avl_link));
+ mutex_init(&cache->pid.mutex, NULL, MUTEX_DEFAULT, NULL);
+ cache->pid.state = CACHE_CREATED;
+ cache->pid.purge_time = 0;
+}
+
+
+void
+kidmap_cache_delete(idmap_cache_t *cache)
+{
+ entry_t *entry;
+ void *cookie;
+
+ cookie = NULL;
+ while ((entry = avl_destroy_nodes(&cache->pid.tree, &cookie))
+ != NULL) {
+ kmem_free(entry, sizeof (entry_t));
+ }
+ avl_destroy(&cache->pid.tree);
+ rw_destroy(&cache->pid.lock);
+ mutex_destroy(&cache->pid.mutex);
+
+ cookie = NULL;
+ while ((entry = avl_destroy_nodes(&cache->sid.tree, &cookie))
+ != NULL) {
+ kmem_free(entry, sizeof (entry_t));
+ }
+ avl_destroy(&cache->sid.tree);
+ rw_destroy(&cache->sid.lock);
+ mutex_destroy(&cache->sid.mutex);
+}
+
+
+int
+kidmap_cache_lookupbypid(idmap_cache_t *cache, const char **sid_prefix,
+ uint32_t *rid, uid_t pid, int is_user)
+
+{
+ entry_t entry;
+ entry_t *result;
+ avl_index_t where;
+ int status;
+ time_t now = gethrestime_sec();
+
+ entry.pid = pid;
+ entry.is_user = is_user;
+
+ rw_enter(&cache->pid.lock, RW_READER);
+
+ result = avl_find(&cache->pid.tree, &entry, &where);
+
+ if (result && result->ttl > now) {
+ *sid_prefix = result->sid_prefix;
+ *rid = result->rid;
+ status = IDMAP_SUCCESS;
+ } else
+ status = IDMAP_ERR_NOMAPPING;
+
+ rw_exit(&cache->pid.lock);
+
+ return (status);
+}
+
+
+int
+kidmap_cache_lookupbysid(idmap_cache_t *cache, const char *sid_prefix,
+ uint32_t rid, uid_t *pid, int *is_user)
+{
+ entry_t entry;
+ entry_t *result;
+ avl_index_t where;
+ int status;
+ time_t now = gethrestime_sec();
+
+ entry.sid_prefix = sid_prefix;
+ entry.rid = rid;
+
+ rw_enter(&cache->sid.lock, RW_READER);
+
+ result = avl_find(&cache->sid.tree, &entry, &where);
+
+ if (result && result->ttl > now) {
+ *pid = result->pid;
+ *is_user = result->is_user;
+ status = IDMAP_SUCCESS;
+ } else
+ status = IDMAP_ERR_NOMAPPING;
+
+ rw_exit(&cache->sid.lock);
+
+ return (status);
+}
+
+
+void
+kidmap_cache_addbypid(idmap_cache_t *cache, const char *sid_prefix,
+ uint32_t rid, uid_t pid, int is_user, time_t ttl)
+{
+ entry_t find;
+ entry_t *result;
+ entry_t *new;
+ avl_index_t where;
+ int purge_required = FALSE;
+
+ find.pid = pid;
+ find.is_user = is_user;
+
+ rw_enter(&cache->pid.lock, RW_WRITER);
+ result = avl_find(&cache->pid.tree, &find, &where);
+
+ if (result) {
+ result->sid_prefix = sid_prefix;
+ result->rid = rid;
+ result->ttl = ttl;
+ } else {
+ new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
+ new->pid = pid;
+ new->is_user = is_user;
+ new->sid_prefix = sid_prefix;
+ new->rid = rid;
+ new->ttl = ttl;
+
+ avl_insert(&cache->pid.tree, new, where);
+ if ((avl_numnodes(&cache->pid.tree) > CACHE_TRIGGER_SIZE) &&
+ (cache->pid.purge_time + CACHE_PURGE_INTERVAL <
+ gethrestime_sec()))
+ purge_required = TRUE;
+ }
+
+ rw_exit(&cache->pid.lock);
+
+ if (purge_required)
+ kidmap_cache_purge_avl(&cache->pid);
+}
+
+
+void
+kidmap_cache_addbysid(idmap_cache_t *cache, const char *sid_prefix,
+ uint32_t rid, uid_t pid, int is_user, time_t ttl)
+
+{
+ entry_t find;
+ entry_t *result;
+ entry_t *new;
+ avl_index_t where;
+ int purge_required = FALSE;
+
+ find.sid_prefix = sid_prefix;
+ find.rid = rid;
+
+ rw_enter(&cache->sid.lock, RW_WRITER);
+ result = avl_find(&cache->sid.tree, &find, &where);
+
+ if (result) {
+ result->pid = pid;
+ result->is_user = is_user;
+ result->ttl = ttl;
+ } else {
+ new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
+ new->pid = pid;
+ new->is_user = is_user;
+ new->sid_prefix = sid_prefix;
+ new->rid = rid;
+ new->ttl = ttl;
+
+ avl_insert(&cache->sid.tree, new, where);
+
+ if ((avl_numnodes(&cache->sid.tree) > CACHE_TRIGGER_SIZE) &&
+ (cache->sid.purge_time + CACHE_PURGE_INTERVAL <
+ gethrestime_sec()))
+ purge_required = TRUE;
+ }
+
+ rw_exit(&cache->sid.lock);
+
+ if (purge_required)
+ kidmap_cache_purge_avl(&cache->sid);
+}
+
+
+static void
+kidmap_cache_purge_avl(idmap_avl_cache_t *cache)
+{
+ time_t now = gethrestime_sec();
+ entry_t *curr;
+ entry_t *prev = NULL;
+
+ mutex_enter(&cache->mutex);
+ if (cache->state != CACHE_CREATED) {
+ mutex_exit(&cache->mutex);
+ return;
+ }
+ cache->state = CACHE_PURGING;
+ mutex_exit(&cache->mutex);
+
+ rw_enter(&cache->lock, RW_READER);
+ curr = avl_first(&cache->tree);
+ while (curr != NULL) {
+ if (curr->ttl < now) {
+ /* Old entry to remove - we need a write lock */
+ if (rw_tryupgrade(&cache->lock) == 0) {
+ /*
+ * Could not upgrade lock so release lock
+ * and aquire the write lock. It is valid to
+ * release abd re-aquire the lock as there
+ * can only be one purge routine running on an
+ * avl tree and no other routine removes
+ * entries.
+ */
+ rw_exit(&cache->lock);
+ rw_enter(&cache->lock, RW_WRITER);
+ }
+ /* Old entry to remove */
+ avl_remove(&cache->tree, curr);
+ rw_downgrade(&cache->lock);
+
+ curr = prev;
+ if (curr == NULL) {
+ /* We removed the first entery */
+ curr = avl_first(&cache->tree);
+ continue;
+ }
+ }
+ prev = curr;
+ curr = AVL_NEXT(&cache->tree, curr);
+ }
+ rw_exit(&cache->lock);
+
+ mutex_enter(&cache->mutex);
+ cache->state = CACHE_CREATED;
+ cache->purge_time = now;
+ mutex_exit(&cache->mutex);
+}
+
+void
+kidmap_sid_prefix_store_init(void)
+{
+ kidmap_sid_prefix_store = (struct sid_prefix_store *)
+ space_fetch("SUNW,idmap_sid_prefix");
+ if (kidmap_sid_prefix_store == NULL) {
+ kidmap_sid_prefix_store = kmem_alloc(
+ sizeof (struct sid_prefix_store), KM_SLEEP);
+ rw_init(&kidmap_sid_prefix_store->lock, NULL, RW_DRIVER, NULL);
+ avl_create(&kidmap_sid_prefix_store->tree,
+ (avl_comp_fn)kidmap_compare_sid_prefix,
+ sizeof (sid_prefix_node_t),
+ offsetof(sid_prefix_node_t, avl_link));
+ (void) space_store("SUNW,idmap_sid_prefix",
+ (uintptr_t)kidmap_sid_prefix_store);
+ } else {
+ /*
+ * The AVL comparison function must be re-initialised on
+ * re-load because may not be loaded into the same
+ * address space.
+ */
+ kidmap_sid_prefix_store->tree.avl_compar =
+ (avl_comp_fn)kidmap_compare_sid_prefix;
+ }
+}
+
+
+const char *
+kidmap_find_sid_prefix(const char *sid_prefix) {
+ sid_prefix_node_t find;
+ sid_prefix_node_t *result;
+ sid_prefix_node_t *new;
+ avl_index_t where;
+
+ if (sid_prefix == NULL || *sid_prefix == '\0')
+ return (NULL);
+
+ find.sid_prefix = sid_prefix;
+
+
+ rw_enter(&kidmap_sid_prefix_store->lock, RW_READER);
+
+ result = avl_find(&kidmap_sid_prefix_store->tree, &find, &where);
+
+ if (result) {
+ rw_exit(&kidmap_sid_prefix_store->lock);
+ return (result->sid_prefix);
+ }
+
+ if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) {
+ /*
+ * Could not upgrade lock so release lock
+ * and aquire the write lock
+ */
+ rw_exit(&kidmap_sid_prefix_store->lock);
+ rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER);
+
+ result = avl_find(&kidmap_sid_prefix_store->tree,
+ &find, &where);
+ if (result) {
+ rw_exit(&kidmap_sid_prefix_store->lock);
+ return (result->sid_prefix);
+ }
+ }
+
+ new = kmem_alloc(sizeof (sid_prefix_node_t), KM_SLEEP);
+ new->sid_prefix = kidmap_strdup(sid_prefix);
+ avl_insert(&kidmap_sid_prefix_store->tree, new, where);
+ rw_exit(&kidmap_sid_prefix_store->lock);
+
+ return (new->sid_prefix);
+}
diff --git a/usr/src/uts/common/idmap/idmap_kapi.c b/usr/src/uts/common/idmap/idmap_kapi.c
new file mode 100644
index 0000000000..b2dd477c9b
--- /dev/null
+++ b/usr/src/uts/common/idmap/idmap_kapi.c
@@ -0,0 +1,1318 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Windows to Solaris Identity Mapping kernel API
+ * This module provides an API to map Windows SIDs to
+ * Solaris UID and GIDs.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/ksynch.h>
+#include <sys/door.h>
+#include <rpc/rpc_msg.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/rpc_sztypes.h>
+#ifdef DEBUG
+#include <sys/cmn_err.h>
+#endif /* DEBUG */
+#include <sys/proc.h>
+#include <sys/sunddi.h>
+#include <sys/param.h>
+#include <sys/atomic.h>
+#include <sys/sysmacros.h>
+#include <sys/disp.h>
+#include <sys/kidmap.h>
+#include "idmap_prot.h"
+#include "kidmap_priv.h"
+
+#define CACHE_TTL (60 * 10)
+
+
+static kmutex_t idmap_lock;
+static idmap_cache_t idmap_cache;
+
+/*
+ * Used to hold RPC header, in particular the XID (not that XID matters
+ * in doors RPC)
+ */
+static struct rpc_msg call_msg;
+
+typedef struct idmap_get_res {
+ idmap_id_type idtype;
+ uid_t *uid;
+ gid_t *gid;
+ int *is_user;
+ const char **sid_prefix;
+ uint32_t *rid;
+ idmap_stat *stat;
+} idmap_get_res;
+
+/* Batch mapping handle structure */
+struct idmap_get_handle {
+ idmap_cache_t *cache;
+ int mapping_num;
+ int mapping_size;
+ idmap_mapping *mapping;
+ idmap_get_res *result;
+};
+
+static kmutex_t idmap_mutex;
+static int idmap_stopped = 0;
+
+struct idmap_reg {
+ door_handle_t idmap_door;
+ int idmap_invalid;
+ int idmap_invalidated;
+ int idmap_ref;
+};
+
+static idmap_reg_t *idmap_ptr;
+
+
+static int
+kidmap_rpc_call(uint32_t op, xdrproc_t xdr_args, caddr_t args,
+ xdrproc_t xdr_res, caddr_t res);
+
+static int kidmap_call_door(door_arg_t *arg);
+
+#ifdef DEBUG
+static int kidmap_rpc_ping(void);
+#endif /* DEBUG */
+
+static void
+idmap_freeone(idmap_reg_t *p)
+{
+ ASSERT(p->idmap_ref == 0);
+ ASSERT(MUTEX_HELD(&idmap_mutex));
+
+ door_ki_rele(p->idmap_door);
+ if (idmap_ptr == p)
+ idmap_ptr = NULL;
+
+ kmem_free(p, sizeof (*p));
+}
+
+void
+idmap_get_door(idmap_reg_t **state, door_handle_t *dh)
+{
+ idmap_reg_t *idmp;
+
+ *state = NULL;
+ if (dh != NULL)
+ *dh = NULL;
+
+ mutex_enter(&idmap_mutex);
+ if ((idmp = idmap_ptr) == NULL || idmp->idmap_invalid) {
+ mutex_exit(&idmap_mutex);
+ return;
+ }
+
+ idmap_ptr->idmap_ref++;
+
+ mutex_exit(&idmap_mutex);
+
+ *state = idmp;
+ if (dh != NULL)
+ *dh = idmp->idmap_door;
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "idmap: Using door_handle_t %p",
+ (dh != NULL) ? (void*)*dh : NULL);
+#endif /* DEBUG */
+}
+
+void
+idmap_release_door(idmap_reg_t *idmp)
+{
+ mutex_enter(&idmap_mutex);
+
+ /*
+ * Note we may decrement idmap_ref twice; if we do it's because
+ * we had EBADF, and rather than decrement the ref count where
+ * that happens we do it here to make sure that we do both
+ * decrements while holding idmap_mutex.
+ */
+ if (idmp->idmap_invalid && !idmp->idmap_invalidated) {
+ idmp->idmap_invalidated = 1;
+ if (--idmp->idmap_ref == 0) {
+ idmap_freeone(idmap_ptr);
+ mutex_exit(&idmap_mutex);
+ return;
+ }
+ }
+
+ if (--idmp->idmap_ref == 0)
+ idmap_freeone(idmap_ptr);
+
+ mutex_exit(&idmap_mutex);
+}
+
+int
+idmap_reg_dh(door_handle_t dh)
+{
+ idmap_reg_t *idmp;
+#ifdef DEBUG
+ int status;
+#endif /* DEBUG */
+
+ idmp = kmem_alloc(sizeof (*idmp), KM_SLEEP);
+
+ idmp->idmap_door = dh;
+ mutex_enter(&idmap_mutex);
+
+
+ if (idmap_stopped) {
+ mutex_exit(&idmap_mutex);
+ /*
+ * We're unloading the module. Calling idmap_reg(2)
+ * again once we're done unloading should cause the
+ * module to be loaded again, so we return EAGAIN.
+ */
+ return (EAGAIN);
+ }
+
+ if (idmap_ptr != NULL) {
+ if (--idmap_ptr->idmap_ref == 0)
+ idmap_freeone(idmap_ptr);
+ }
+ idmp->idmap_invalid = 0;
+ idmp->idmap_invalidated = 0;
+ idmp->idmap_ref = 1;
+ idmap_ptr = idmp;
+
+ call_msg.rm_xid = 1;
+ call_msg.rm_call.cb_prog = IDMAP_PROG;
+ call_msg.rm_call.cb_vers = IDMAP_V1;
+
+ mutex_exit(&idmap_mutex);
+
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "idmap: Registered door_handle_t %p", (void *)dh);
+ if ((status = kidmap_rpc_ping()) != 0)
+ cmn_err(CE_WARN, "idmap: Door RPC ping failed %d\n", status);
+#endif /* DEBUG */
+
+ return (0);
+}
+
+int
+idmap_unreg_dh(door_handle_t dh)
+{
+ mutex_enter(&idmap_mutex);
+ if (idmap_ptr == NULL || idmap_ptr->idmap_door != dh) {
+ mutex_exit(&idmap_mutex);
+ return (EINVAL);
+ }
+
+ if (idmap_ptr->idmap_invalid) {
+ mutex_exit(&idmap_mutex);
+ return (EINVAL);
+ }
+ idmap_ptr->idmap_invalid = 1;
+ idmap_ptr->idmap_invalidated = 1;
+ if (--idmap_ptr->idmap_ref == 0)
+ idmap_freeone(idmap_ptr);
+ mutex_exit(&idmap_mutex);
+ return (0);
+}
+
+
+static int
+kidmap_call_door(door_arg_t *arg)
+{
+ int status = 0;
+ door_handle_t dh;
+ idmap_reg_t *reg;
+
+ idmap_get_door(&reg, &dh);
+ if (reg == NULL || dh == NULL) {
+ return (-1);
+ }
+
+ status = door_ki_upcall(dh, arg);
+
+#ifdef DEBUG
+ if (status != 0)
+ cmn_err(CE_WARN, "idmap: Door call failed %d\n", status);
+#endif /* DEBUG */
+
+ if (status == EBADF) {
+ reg->idmap_invalid = 1;
+ }
+
+ idmap_release_door(reg);
+
+ return (status);
+}
+
+
+int
+kidmap_start(void)
+{
+ mutex_init(&idmap_lock, NULL, MUTEX_DEFAULT, NULL);
+ kidmap_sid_prefix_store_init();
+ kidmap_cache_create(&idmap_cache);
+
+ idmap_stopped = 0;
+
+ return (0);
+}
+
+
+int
+kidmap_stop(void)
+{
+ mutex_enter(&idmap_mutex);
+
+ if (idmap_ptr != NULL) {
+ mutex_exit(&idmap_mutex);
+ return (EBUSY);
+ }
+
+ idmap_stopped = 1;
+
+ mutex_exit(&idmap_mutex);
+
+ kidmap_cache_delete(&idmap_cache);
+ mutex_destroy(&idmap_lock);
+
+ return (0);
+}
+
+
+/*
+ * Given Domain SID and RID, get UID
+ *
+ * Input:
+ * sid_prefix - Domain SID in canonical form
+ * rid - RID
+ *
+ * Output:
+ * uid - POSIX UID if return == IDMAP_SUCCESS
+ *
+ * Return:
+ * Success return IDMAP_SUCCESS else IDMAP error
+ */
+idmap_stat
+kidmap_getuidbysid(const char *sid_prefix, uint32_t rid, uid_t *uid)
+{
+ idmap_mapping_batch args;
+ idmap_mapping mapping;
+ idmap_ids_res results;
+ uint32_t op = IDMAP_GET_MAPPED_IDS;
+ int is_user;
+ const char *new_sid_prefix;
+ idmap_stat status;
+ time_t entry_ttl;
+
+ if (sid_prefix == NULL || uid == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbysid(&idmap_cache, sid_prefix,
+ rid, uid, &is_user) == IDMAP_SUCCESS && is_user == 1) {
+ return (IDMAP_SUCCESS);
+ }
+
+ bzero(&mapping, sizeof (idmap_mapping));
+ mapping.id1.idtype = IDMAP_SID;
+ mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
+ mapping.id1.idmap_id_u.sid.rid = rid;
+ mapping.id2.idtype = IDMAP_UID;
+
+ bzero(&results, sizeof (idmap_ids_res));
+
+ args.idmap_mapping_batch_len = 1;
+ args.idmap_mapping_batch_val = &mapping;
+
+ if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
+ (caddr_t)&args, xdr_idmap_ids_res,
+ (caddr_t)&results) == 0) {
+ /* Door call succeded */
+ if (results.ids.ids_len >= 1 &&
+ results.ids.ids_val[0].id.idtype == IDMAP_UID) {
+ status = results.ids.ids_val[0].retcode;
+ *uid = results.ids.ids_val[0].id.idmap_id_u.uid;
+ if (status == IDMAP_SUCCESS) {
+ entry_ttl = CACHE_TTL + gethrestime_sec();
+ new_sid_prefix = kidmap_find_sid_prefix(
+ sid_prefix);
+ kidmap_cache_addbysid(&idmap_cache,
+ new_sid_prefix, rid,
+ *uid, 1, entry_ttl);
+ }
+ } else {
+ status = IDMAP_ERR_NOMAPPING;
+ *uid = UID_NOBODY;
+ }
+ xdr_free(xdr_idmap_ids_res, (char *)&results);
+ } else {
+ /* Door call failed */
+ status = IDMAP_ERR_NOMAPPING;
+ *uid = UID_NOBODY;
+ }
+ return (status);
+}
+
+
+/*
+ * Given Domain SID and RID, get GID
+ *
+ * Input:
+ * sid_prefix - Domain SID in canonical form
+ * rid - RID
+ *
+ * Output:
+ * gid - POSIX UID if return == IDMAP_SUCCESS
+ *
+ * Return:
+ * Success return IDMAP_SUCCESS else IDMAP error
+ */
+idmap_stat
+kidmap_getgidbysid(const char *sid_prefix, uint32_t rid, gid_t *gid)
+{
+ idmap_mapping_batch args;
+ idmap_mapping mapping;
+ idmap_ids_res results;
+ uint32_t op = IDMAP_GET_MAPPED_IDS;
+ int is_user;
+ const char *new_sid_prefix;
+ idmap_stat status;
+ time_t entry_ttl;
+
+ if (sid_prefix == NULL || gid == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbysid(&idmap_cache, sid_prefix,
+ rid, gid, &is_user) == IDMAP_SUCCESS && is_user == 0) {
+ return (IDMAP_SUCCESS);
+ }
+
+ bzero(&mapping, sizeof (idmap_mapping));
+ mapping.id1.idtype = IDMAP_SID;
+ mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
+ mapping.id1.idmap_id_u.sid.rid = rid;
+ mapping.id2.idtype = IDMAP_GID;
+
+ bzero(&results, sizeof (idmap_ids_res));
+
+ args.idmap_mapping_batch_len = 1;
+ args.idmap_mapping_batch_val = &mapping;
+
+ if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
+ (caddr_t)&args, xdr_idmap_ids_res,
+ (caddr_t)&results) == 0) {
+ /* Door call succeded */
+ if (results.ids.ids_len >= 1 &&
+ results.ids.ids_val[0].id.idtype == IDMAP_GID) {
+ status = results.ids.ids_val[0].retcode;
+ *gid = results.ids.ids_val[0].id.idmap_id_u.gid;
+ if (status == IDMAP_SUCCESS) {
+ entry_ttl = CACHE_TTL + gethrestime_sec();
+ new_sid_prefix = kidmap_find_sid_prefix(
+ sid_prefix);
+ kidmap_cache_addbysid(&idmap_cache,
+ new_sid_prefix, rid,
+ *gid, 0, entry_ttl);
+ }
+ } else {
+ status = IDMAP_ERR_NOMAPPING;
+ *gid = GID_NOBODY;
+ }
+ xdr_free(xdr_idmap_ids_res, (char *)&results);
+ } else {
+ /* Door call failed */
+ status = IDMAP_ERR_NOMAPPING;
+ *gid = GID_NOBODY;
+ }
+ return (status);
+}
+
+/*
+ * Given Domain SID and RID, get Posix ID
+ *
+ * Input:
+ * sid_prefix - Domain SID in canonical form
+ * rid - RID
+ *
+ * Output:
+ * pid - POSIX ID if return == IDMAP_SUCCESS
+ * is_user - 1 == UID, 0 == GID if return == IDMAP_SUCCESS
+ *
+ * Return:
+ * Success return IDMAP_SUCCESS else IDMAP error
+ */
+idmap_stat
+kidmap_getpidbysid(const char *sid_prefix, uint32_t rid, uid_t *pid,
+ int *is_user)
+{
+ idmap_mapping_batch args;
+ idmap_mapping mapping;
+ idmap_ids_res results;
+ uint32_t op = IDMAP_GET_MAPPED_IDS;
+ const char *new_sid_prefix;
+ idmap_stat status;
+ time_t entry_ttl;
+
+ if (sid_prefix == NULL || pid == NULL || is_user == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbysid(&idmap_cache, sid_prefix, rid, pid,
+ is_user) == IDMAP_SUCCESS) {
+ return (IDMAP_SUCCESS);
+ }
+
+ bzero(&mapping, sizeof (idmap_mapping));
+ mapping.id1.idtype = IDMAP_SID;
+ mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
+ mapping.id1.idmap_id_u.sid.rid = rid;
+ mapping.id2.idtype = IDMAP_POSIXID;
+
+ bzero(&results, sizeof (idmap_ids_res));
+
+ args.idmap_mapping_batch_len = 1;
+ args.idmap_mapping_batch_val = &mapping;
+
+ if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
+ (caddr_t)&args, xdr_idmap_ids_res,
+ (caddr_t)&results) == 0) {
+ /* Door call succeded */
+ if (results.ids.ids_len >= 1 && (
+ results.ids.ids_val[0].id.idtype == IDMAP_UID ||
+ results.ids.ids_val[0].id.idtype == IDMAP_GID)) {
+ status = results.ids.ids_val[0].retcode;
+ if (results.ids.ids_val[0].id.idtype == IDMAP_UID) {
+ *is_user = 1;
+ *pid = results.ids.ids_val[0].id.idmap_id_u.uid;
+ } else {
+ *is_user = 0;
+ *pid = results.ids.ids_val[0].id.idmap_id_u.gid;
+ }
+ if (status == IDMAP_SUCCESS) {
+ entry_ttl = CACHE_TTL + gethrestime_sec();
+ new_sid_prefix = kidmap_find_sid_prefix(
+ sid_prefix);
+ kidmap_cache_addbysid(&idmap_cache,
+ new_sid_prefix, rid, *pid,
+ *is_user, entry_ttl);
+ }
+ } else {
+ status = IDMAP_ERR_NOMAPPING;
+ *is_user = 1;
+ *pid = UID_NOBODY;
+ }
+ xdr_free(xdr_idmap_ids_res, (char *)&results);
+ } else {
+ /* Door call failed */
+ status = IDMAP_ERR_NOMAPPING;
+ *is_user = 1;
+ *pid = UID_NOBODY;
+ }
+ return (status);
+}
+
+
+/*
+ * Given UID, get Domain SID and RID
+ *
+ * Input:
+ * uid - Posix UID
+ *
+ * Output:
+ * sid_prefix - Domain SID if return == IDMAP_SUCCESS
+ * rid - RID if return == IDMAP_SUCCESS
+ *
+ * Return:
+ * Success return IDMAP_SUCCESS else IDMAP error
+ */
+idmap_stat
+kidmap_getsidbyuid(uid_t uid, const char **sid_prefix, uint32_t *rid)
+{
+ idmap_mapping_batch args;
+ idmap_mapping mapping;
+ idmap_ids_res results;
+ uint32_t op = IDMAP_GET_MAPPED_IDS;
+ idmap_stat status;
+ time_t entry_ttl;
+ idmap_id *id;
+
+ if (sid_prefix == NULL || rid == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbypid(&idmap_cache, sid_prefix, rid, uid, 1)
+ == IDMAP_SUCCESS) {
+ return (IDMAP_SUCCESS);
+ }
+
+ bzero(&mapping, sizeof (idmap_mapping));
+ mapping.id1.idtype = IDMAP_UID;
+ mapping.id1.idmap_id_u.uid = uid;
+ mapping.id2.idtype = IDMAP_SID;
+
+ bzero(&results, sizeof (idmap_ids_res));
+
+ args.idmap_mapping_batch_len = 1;
+ args.idmap_mapping_batch_val = &mapping;
+
+ if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
+ (caddr_t)&args, xdr_idmap_ids_res,
+ (caddr_t)&results) == 0) {
+ /* Door call succeded */
+ if (results.ids.ids_len >= 1 &&
+ results.ids.ids_val[0].id.idtype == IDMAP_SID) {
+ status = results.ids.ids_val[0].retcode;
+ id = &results.ids.ids_val[0].id;
+ *sid_prefix = kidmap_find_sid_prefix(
+ id->idmap_id_u.sid.prefix);
+ *rid = id->idmap_id_u.sid.rid;
+ if (status == IDMAP_SUCCESS) {
+ entry_ttl = CACHE_TTL + gethrestime_sec();
+ kidmap_cache_addbypid(&idmap_cache,
+ *sid_prefix, *rid, uid,
+ 1, entry_ttl);
+ }
+ } else {
+ status = IDMAP_ERR_NOMAPPING;
+ *rid = 0;
+ *sid_prefix = NULL;
+ }
+ xdr_free(xdr_idmap_ids_res, (char *)&results);
+ } else {
+ /* Door call failed */
+ status = IDMAP_ERR_NOMAPPING;
+ *rid = 0;
+ *sid_prefix = NULL;
+ }
+ return (status);
+}
+
+
+/*
+ * Given GID, get Domain SID and RID
+ *
+ * Input:
+ * gid - Posix GID
+ *
+ * Output:
+ * sid_prefix - Domain SID if return == IDMAP_SUCCESS
+ * rid - RID if return == IDMAP_SUCCESS
+ *
+ * Return:
+ * Success return IDMAP_SUCCESS else IDMAP error
+ */
+idmap_stat
+kidmap_getsidbygid(gid_t gid, const char **sid_prefix, uint32_t *rid)
+{
+ idmap_mapping_batch args;
+ idmap_mapping mapping;
+ idmap_ids_res results;
+ uint32_t op = IDMAP_GET_MAPPED_IDS;
+ idmap_stat status;
+ time_t entry_ttl;
+ idmap_id *id;
+
+ if (sid_prefix == NULL || rid == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbypid(&idmap_cache, sid_prefix, rid, gid, 0)
+ == IDMAP_SUCCESS) {
+ return (IDMAP_SUCCESS);
+ }
+
+ bzero(&mapping, sizeof (idmap_mapping));
+ mapping.id1.idtype = IDMAP_GID;
+ mapping.id1.idmap_id_u.uid = gid;
+ mapping.id2.idtype = IDMAP_SID;
+
+ bzero(&results, sizeof (idmap_ids_res));
+
+ args.idmap_mapping_batch_len = 1;
+ args.idmap_mapping_batch_val = &mapping;
+
+ if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
+ (caddr_t)&args, xdr_idmap_ids_res,
+ (caddr_t)&results) == 0) {
+ /* Door call succeded */
+ if (results.ids.ids_len >= 1 &&
+ results.ids.ids_val[0].id.idtype == IDMAP_SID) {
+ status = results.ids.ids_val[0].retcode;
+ id = &results.ids.ids_val[0].id;
+ *sid_prefix = kidmap_find_sid_prefix(
+ id->idmap_id_u.sid.prefix);
+ *rid = id->idmap_id_u.sid.rid;
+ if (status == IDMAP_SUCCESS) {
+ entry_ttl = CACHE_TTL + gethrestime_sec();
+ kidmap_cache_addbypid(&idmap_cache,
+ *sid_prefix, *rid, gid,
+ 0, entry_ttl);
+ }
+ } else {
+ status = IDMAP_ERR_NOMAPPING;
+ *rid = 0;
+ *sid_prefix = NULL;
+ }
+ xdr_free(xdr_idmap_ids_res, (char *)&results);
+ } else {
+ /* Door call failed */
+ status = IDMAP_ERR_NOMAPPING;
+ *rid = 0;
+ *sid_prefix = NULL;
+ }
+ return (status);
+}
+
+/*
+ * Create handle to get SID to UID/GID mapping entries
+ *
+ * Input:
+ * none
+ * Return:
+ * get_handle
+ *
+ */
+idmap_get_handle_t *
+kidmap_get_create(void)
+{
+ idmap_get_handle_t *handle;
+#define INIT_MAPPING_SIZE 6
+
+ handle = kmem_zalloc(sizeof (idmap_get_handle_t), KM_SLEEP);
+
+ handle->mapping = kmem_zalloc((sizeof (idmap_mapping)) *
+ INIT_MAPPING_SIZE, KM_SLEEP);
+
+ handle->result = kmem_zalloc((sizeof (idmap_get_res)) *
+ INIT_MAPPING_SIZE, KM_SLEEP);
+ handle->mapping_size = INIT_MAPPING_SIZE;
+ handle->cache = &idmap_cache;
+
+ return (handle);
+}
+
+/*
+ * Internal routine to extend a "get_handle"
+ */
+static void
+kidmap_get_extend(idmap_get_handle_t *get_handle)
+{
+ idmap_mapping *mapping;
+ idmap_get_res *result;
+ int new_size = get_handle->mapping_size + INIT_MAPPING_SIZE;
+
+ mapping = kmem_zalloc((sizeof (idmap_mapping)) *
+ new_size, KM_SLEEP);
+ (void) memcpy(mapping, get_handle->mapping,
+ (sizeof (idmap_mapping)) * get_handle->mapping_size);
+
+ result = kmem_zalloc((sizeof (idmap_get_res)) *
+ new_size, KM_SLEEP);
+ (void) memcpy(result, get_handle->result,
+ (sizeof (idmap_get_res)) * get_handle->mapping_size);
+
+ kmem_free(get_handle->mapping,
+ (sizeof (idmap_mapping)) * get_handle->mapping_size);
+ get_handle->mapping = mapping;
+
+ kmem_free(get_handle->result,
+ (sizeof (idmap_get_res)) * get_handle->mapping_size);
+ get_handle->result = result;
+
+ get_handle->mapping_size = new_size;
+}
+
+
+/*
+ * Given Domain SID and RID, get UID
+ *
+ * Input:
+ * sid_prefix - Domain SID in canonical form
+ * rid - RID
+ *
+ * Output:
+ * stat - status of the get request
+ * uid - POSIX UID if stat == IDMAP_SUCCESS
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
+ uint32_t rid, uid_t *uid, idmap_stat *stat)
+{
+ idmap_mapping *mapping;
+ idmap_get_res *result;
+ int is_user;
+
+ if (get_handle == NULL || sid_prefix == NULL ||
+ uid == NULL || stat == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbysid(get_handle->cache, sid_prefix,
+ rid, uid, &is_user) == IDMAP_SUCCESS && is_user == 1) {
+ *stat = IDMAP_SUCCESS;
+ return (IDMAP_SUCCESS);
+ }
+
+ if (get_handle->mapping_num >= get_handle->mapping_size)
+ kidmap_get_extend(get_handle);
+
+ mapping = &get_handle->mapping[get_handle->mapping_num];
+ mapping->flag = 0;
+ mapping->id1.idtype = IDMAP_SID;
+ mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
+ mapping->id1.idmap_id_u.sid.rid = rid;
+ mapping->id2.idtype = IDMAP_UID;
+
+ result = &get_handle->result[get_handle->mapping_num];
+ result->idtype = IDMAP_UID;
+ result->uid = uid;
+ result->gid = NULL;
+ result->sid_prefix = NULL;
+ result->rid = NULL;
+ result->is_user = NULL;
+ result->stat = stat;
+
+ get_handle->mapping_num++;
+
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Given Domain SID and RID, get GID
+ *
+ * Input:
+ * sid_prefix - Domain SID in canonical form
+ * rid - RID
+ *
+ * Output:
+ * stat - status of the get request
+ * gid - POSIX GID if stat == IDMAP_SUCCESS
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
+ uint32_t rid, uid_t *gid, idmap_stat *stat)
+{
+ idmap_mapping *mapping;
+ idmap_get_res *result;
+ int is_user;
+
+ if (get_handle == NULL || sid_prefix == NULL ||
+ gid == NULL || stat == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbysid(get_handle->cache, sid_prefix,
+ rid, gid, &is_user) == IDMAP_SUCCESS && is_user == 0) {
+ *stat = IDMAP_SUCCESS;
+ return (IDMAP_SUCCESS);
+ }
+
+ if (get_handle->mapping_num >= get_handle->mapping_size)
+ kidmap_get_extend(get_handle);
+
+ mapping = &get_handle->mapping[get_handle->mapping_num];
+ mapping->flag = 0;
+ mapping->id1.idtype = IDMAP_SID;
+ mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
+ mapping->id1.idmap_id_u.sid.rid = rid;
+ mapping->id2.idtype = IDMAP_GID;
+
+ result = &get_handle->result[get_handle->mapping_num];
+ result->idtype = IDMAP_GID;
+ result->uid = NULL;
+ result->gid = gid;
+ result->sid_prefix = NULL;
+ result->rid = NULL;
+ result->is_user = NULL;
+ result->stat = stat;
+
+ get_handle->mapping_num++;
+
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Given Domain SID and RID, get Posix ID
+ *
+ * Input:
+ * sid_prefix - Domain SID in canonical form
+ * rid - RID
+ *
+ * Output:
+ * stat - status of the get request
+ * is_user - user or group
+ * pid - POSIX UID if stat == IDMAP_SUCCESS and is_user == 1
+ * POSIX GID if stat == IDMAP_SUCCESS and is_user == 0
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
+ uint32_t rid, uid_t *pid, int *is_user, idmap_stat *stat)
+{
+ idmap_mapping *mapping;
+ idmap_get_res *result;
+
+ if (get_handle == NULL || sid_prefix == NULL || pid == NULL ||
+ is_user == NULL || stat == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbysid(get_handle->cache, sid_prefix,
+ rid, pid, is_user) == IDMAP_SUCCESS) {
+ *stat = IDMAP_SUCCESS;
+ return (IDMAP_SUCCESS);
+ }
+
+
+ if (get_handle->mapping_num >= get_handle->mapping_size)
+ kidmap_get_extend(get_handle);
+
+ mapping = &get_handle->mapping[get_handle->mapping_num];
+ mapping->flag = 0;
+ mapping->id1.idtype = IDMAP_SID;
+ mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
+ mapping->id1.idmap_id_u.sid.rid = rid;
+ mapping->id2.idtype = IDMAP_POSIXID;
+
+ result = &get_handle->result[get_handle->mapping_num];
+ result->idtype = IDMAP_POSIXID;
+ result->uid = pid;
+ result->gid = pid;
+ result->sid_prefix = NULL;
+ result->rid = NULL;
+ result->is_user = is_user;
+ result->stat = stat;
+
+ get_handle->mapping_num++;
+
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Given UID, get SID and RID
+ *
+ * Input:
+ * uid - POSIX UID
+ *
+ * Output:
+ * stat - status of the get request
+ * sid - SID in canonical form (if stat == IDMAP_SUCCESS)
+ * rid - RID (if stat == IDMAP_SUCCESS)
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
+{
+ idmap_mapping *mapping;
+ idmap_get_res *result;
+
+ if (get_handle == NULL || sid_prefix == NULL ||
+ rid == NULL || stat == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbypid(get_handle->cache, sid_prefix, rid, uid, 1)
+ == IDMAP_SUCCESS) {
+ *stat = IDMAP_SUCCESS;
+ return (IDMAP_SUCCESS);
+ }
+
+ if (get_handle->mapping_num >= get_handle->mapping_size)
+ kidmap_get_extend(get_handle);
+
+ mapping = &get_handle->mapping[get_handle->mapping_num];
+ mapping->flag = 0;
+ mapping->id1.idtype = IDMAP_UID;
+ mapping->id1.idmap_id_u.uid = uid;
+ mapping->id2.idtype = IDMAP_SID;
+
+ result = &get_handle->result[get_handle->mapping_num];
+ result->idtype = IDMAP_SID;
+ result->uid = NULL;
+ result->gid = NULL;
+ result->sid_prefix = sid_prefix;
+ result->rid = rid;
+ result->is_user = NULL;
+ result->stat = stat;
+
+ get_handle->mapping_num++;
+
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Given GID, get SID and RID
+ *
+ * Input:
+ * gid - POSIX GID
+ *
+ * Output:
+ * stat - status of the get request
+ * sid - SID in canonical form (if stat == IDMAP_SUCCESS)
+ * rid - RID (if stat == IDMAP_SUCCESS)
+ *
+ * Note: The output parameters will be set by idmap_get_mappings()
+ */
+idmap_stat
+kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
+{
+ idmap_mapping *mapping;
+ idmap_get_res *result;
+
+ if (get_handle == NULL || sid_prefix == NULL ||
+ rid == NULL || stat == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (kidmap_cache_lookupbypid(get_handle->cache, sid_prefix, rid, gid, 0)
+ == IDMAP_SUCCESS) {
+ *stat = IDMAP_SUCCESS;
+ return (IDMAP_SUCCESS);
+ }
+
+ if (get_handle->mapping_num >= get_handle->mapping_size)
+ kidmap_get_extend(get_handle);
+
+ mapping = &get_handle->mapping[get_handle->mapping_num];
+ mapping->flag = 0;
+ mapping->id1.idtype = IDMAP_GID;
+ mapping->id1.idmap_id_u.gid = gid;
+ mapping->id2.idtype = IDMAP_SID;
+
+ result = &get_handle->result[get_handle->mapping_num];
+ result->idtype = IDMAP_SID;
+ result->uid = NULL;
+ result->gid = NULL;
+ result->sid_prefix = sid_prefix;
+ result->rid = rid;
+ result->is_user = NULL;
+ result->stat = stat;
+
+ get_handle->mapping_num++;
+
+ return (IDMAP_SUCCESS);
+}
+
+
+/*
+ * Process the batched "get mapping" requests. The results (i.e.
+ * status and identity) will be available in the data areas
+ * provided by individual requests.
+ *
+ * If the door call fails the status IDMAP_ERR_NOMAPPING is
+ * return and the UID or UID result is set to "nobody"
+ */
+
+idmap_stat
+kidmap_get_mappings(idmap_get_handle_t *get_handle)
+{
+ idmap_mapping_batch args;
+ idmap_ids_res results;
+ uint32_t op = IDMAP_GET_MAPPED_IDS;
+ idmap_mapping *mapping;
+ idmap_get_res *result;
+ idmap_id *id;
+ int status;
+ int i;
+ const char *sid_prefix;
+ time_t entry_ttl;
+ int is_user;
+
+ if (get_handle == NULL)
+ return (IDMAP_ERR_ARG);
+
+ if (get_handle->mapping_num == 0)
+ return (IDMAP_SUCCESS);
+
+ bzero(&results, sizeof (idmap_ids_res));
+
+ args.idmap_mapping_batch_len = get_handle->mapping_num;
+ args.idmap_mapping_batch_val = get_handle->mapping;
+
+ if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
+ (caddr_t)&args, xdr_idmap_ids_res,
+ (caddr_t)&results) == 0) {
+ /* Door call succeded */
+ status = IDMAP_SUCCESS;
+ entry_ttl = CACHE_TTL + gethrestime_sec();
+ for (i = 0; i < get_handle->mapping_num; i++) {
+ mapping = &get_handle->mapping[i];
+ result = &get_handle->result[i];
+
+ if (i > results.ids.ids_len) {
+ *result->stat = IDMAP_ERR_NOMAPPING;
+ if (result->gid)
+ *result->gid = GID_NOBODY;
+ if (result->uid)
+ *result->uid = UID_NOBODY;
+ if (result->is_user)
+ *result->is_user = 1;
+ if (result->sid_prefix)
+ *result->sid_prefix = NULL;
+ if (result->rid)
+ *result->rid = 0;
+ continue;
+ }
+ *result->stat = results.ids.ids_val[i].retcode;
+
+ id = &results.ids.ids_val[i].id;
+ switch (id->idtype) {
+ case IDMAP_UID:
+ if (result->uid)
+ *result->uid = id->idmap_id_u.uid;
+ if (result->is_user)
+ *result->is_user = 1;
+ if (*result->stat == IDMAP_SUCCESS) {
+ sid_prefix = kidmap_find_sid_prefix(
+ mapping->id1.idmap_id_u.sid.prefix);
+ kidmap_cache_addbysid(get_handle->cache,
+ sid_prefix,
+ mapping->id1.idmap_id_u.sid.rid,
+ id->idmap_id_u.uid,
+ 1, entry_ttl);
+ }
+ break;
+
+ case IDMAP_GID:
+ if (result->gid)
+ *result->gid = id->idmap_id_u.gid;
+ if (result->is_user)
+ *result->is_user = 0;
+ if (*result->stat == IDMAP_SUCCESS) {
+ sid_prefix = kidmap_find_sid_prefix(
+ mapping->id1.idmap_id_u.sid.prefix);
+ kidmap_cache_addbysid(get_handle->cache,
+ sid_prefix,
+ mapping->id1.idmap_id_u.sid.rid,
+ id->idmap_id_u.gid,
+ 0, entry_ttl);
+ }
+ break;
+
+ case IDMAP_SID:
+ sid_prefix = kidmap_find_sid_prefix(
+ id->idmap_id_u.sid.prefix);
+ if (result->sid_prefix && result->rid) {
+ *result->sid_prefix = sid_prefix;
+ *result->rid = id->idmap_id_u.sid.rid;
+ }
+ if (*result->stat == IDMAP_SUCCESS) {
+ if (mapping->id1.idtype == IDMAP_UID)
+ is_user = 1;
+ else
+ is_user = 0;
+ kidmap_cache_addbypid(get_handle->cache,
+ sid_prefix,
+ id->idmap_id_u.sid.rid,
+ mapping->id1.idmap_id_u.uid,
+ is_user, entry_ttl);
+ }
+ break;
+
+ default:
+ *result->stat = IDMAP_ERR_NORESULT;
+ if (result->gid)
+ *result->gid = GID_NOBODY;
+ if (result->uid)
+ *result->uid = UID_NOBODY;
+ if (result->is_user)
+ *result->is_user = 1;
+ if (result->sid_prefix)
+ *result->sid_prefix = NULL;
+ if (result->rid)
+ *result->rid = 0;
+ break;
+ }
+ }
+ xdr_free(xdr_idmap_ids_res, (char *)&results);
+ } else {
+ /* Door call failed */
+ status = IDMAP_ERR_NOMAPPING;
+ for (i = 0; i < get_handle->mapping_num; i++) {
+ result = &get_handle->result[i];
+
+ *result->stat = IDMAP_ERR_NOMAPPING;
+ if (result->gid)
+ *result->gid = GID_NOBODY;
+ if (result->uid)
+ *result->uid = UID_NOBODY;
+ if (result->is_user)
+ *result->is_user = 1;
+ if (result->sid_prefix)
+ *result->sid_prefix = NULL;
+ if (result->rid)
+ *result->rid = 0;
+ }
+ }
+
+ /* Reset get_handle for new resquests */
+ get_handle->mapping_num = 0;
+ return (status);
+}
+
+
+/*
+ * Destroy the "get mapping" handle
+ */
+void
+kidmap_get_destroy(idmap_get_handle_t *get_handle)
+{
+ if (get_handle == NULL)
+ return;
+
+ kmem_free(get_handle->mapping,
+ (sizeof (idmap_mapping)) * get_handle->mapping_size);
+ get_handle->mapping = NULL;
+
+ kmem_free(get_handle->result,
+ (sizeof (idmap_get_res)) * get_handle->mapping_size);
+ get_handle->result = NULL;
+
+ kmem_free(get_handle, sizeof (idmap_get_handle_t));
+}
+
+#ifdef DEBUG
+static int
+kidmap_rpc_ping(void)
+{
+ return (kidmap_rpc_call(0, xdr_void, NULL, xdr_void, NULL));
+}
+#endif /* DEBUG */
+
+static int
+kidmap_rpc_call(uint32_t op, xdrproc_t xdr_args, caddr_t args,
+ xdrproc_t xdr_res, caddr_t res)
+{
+ XDR xdr_ctx;
+ struct rpc_msg reply_msg;
+ char *inbuf_ptr = NULL;
+ size_t inbuf_size = 4096;
+ char *outbuf_ptr = NULL;
+ size_t outbuf_size = 4096;
+ size_t size;
+ int status = 0;
+ door_arg_t params;
+ int retry = 0;
+
+ params.rbuf = NULL;
+ params.rsize = 0;
+
+retry:
+ inbuf_ptr = kmem_alloc(inbuf_size, KM_SLEEP);
+ outbuf_ptr = kmem_alloc(outbuf_size, KM_SLEEP);
+
+ xdrmem_create(&xdr_ctx, inbuf_ptr, inbuf_size, XDR_ENCODE);
+ atomic_inc_32(&call_msg.rm_xid);
+ if (!xdr_callhdr(&xdr_ctx, &call_msg)) {
+#ifdef DEBUG
+ cmn_err(CE_WARN, "idmap: xdr encoding header error");
+#endif /* DEBUG */
+ status = -1;
+ goto exit;
+ }
+
+ if (!xdr_uint32(&xdr_ctx, &op) ||
+ /* Auth none */
+ !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
+ !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
+ /* RPC args */
+ !xdr_args(&xdr_ctx, args)) {
+#ifdef DEBUG
+ cmn_err(CE_WARN, "idmap: xdr encoding error");
+#endif /* DEBUG */
+ if (retry > 2) {
+ status = -1;
+ goto exit;
+ }
+ retry++;
+ if (inbuf_ptr) {
+ kmem_free(inbuf_ptr, inbuf_size);
+ inbuf_ptr = NULL;
+ }
+ if (outbuf_ptr) {
+ kmem_free(outbuf_ptr, outbuf_size);
+ outbuf_ptr = NULL;
+ }
+ if ((size = xdr_sizeof(xdr_args, args)) == 0) {
+#ifdef DEBUG
+ cmn_err(CE_WARN, "idmap: xdr sizeof error");
+#endif /* DEBUG */
+ status = -1;
+ goto exit;
+ }
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "idmap: xdr args size %lu", size);
+#endif /* DEBUG */
+ inbuf_size = size + 1024;
+ outbuf_size = size + 1024;
+ goto retry;
+ }
+
+ params.data_ptr = inbuf_ptr;
+ params.data_size = XDR_GETPOS(&xdr_ctx);
+ params.desc_ptr = NULL;
+ params.desc_num = 0;
+ params.rbuf = outbuf_ptr;
+ params.rsize = outbuf_size;
+
+ if (kidmap_call_door(&params) != 0) {
+ status = -1;
+ goto exit;
+ }
+
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ reply_msg.acpted_rply.ar_results.where = res;
+ reply_msg.acpted_rply.ar_results.proc = xdr_res;
+ xdrmem_create(&xdr_ctx, params.data_ptr, params.data_size, XDR_DECODE);
+ if (xdr_replymsg(&xdr_ctx, &reply_msg)) {
+ if (reply_msg.rm_reply.rp_stat != MSG_ACCEPTED ||
+ reply_msg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
+ status = -1;
+ goto exit;
+ }
+ } else {
+#ifdef DEBUG
+ cmn_err(CE_WARN, "idmap: xdr decoding reply message error");
+#endif /* DEBUG */
+ status = -1;
+ }
+
+exit:
+ if (outbuf_ptr != params.rbuf && params.rbuf != NULL)
+ kmem_free(params.rbuf, params.rsize);
+ if (inbuf_ptr)
+ kmem_free(inbuf_ptr, inbuf_size);
+ if (outbuf_ptr)
+ kmem_free(outbuf_ptr, outbuf_size);
+ return (status);
+}
diff --git a/usr/src/uts/common/idmap/idmap_mod.c b/usr/src/uts/common/idmap/idmap_mod.c
new file mode 100644
index 0000000000..0fff9642f0
--- /dev/null
+++ b/usr/src/uts/common/idmap/idmap_mod.c
@@ -0,0 +1,103 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/modctl.h>
+#ifdef DEBUG
+#include <sys/cmn_err.h>
+#endif /* DEBUG */
+#include <sys/kidmap.h>
+#include "kidmap_priv.h"
+
+
+
+
+extern struct mod_ops mod_miscops;
+
+static struct modlmisc misc =
+{
+ &mod_miscops,
+ "ID Mapping kernel module"
+};
+
+static struct modlinkage linkage =
+{
+ MODREV_1,
+ (void *) &misc,
+ NULL
+};
+
+
+int
+_init()
+{
+ int i;
+
+ if ((i = mod_install(&linkage)) != 0) {
+#ifdef DEBUG
+ cmn_err(CE_WARN, "idmap: Failed to load kernel module");
+#endif /* DEBUG */
+ return (i);
+ }
+
+ if (kidmap_start() != 0) {
+#ifdef DEBUG
+ cmn_err(CE_WARN, "idmap: Failed to start");
+#endif /* DEBUG */
+ return (i);
+ }
+
+ return (i);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&linkage, modinfop));
+}
+
+int
+_fini()
+{
+ int i;
+ idmap_reg_t *reg;
+
+ if ((i = kidmap_stop()) != 0) {
+ return (i);
+ }
+
+ if ((i = mod_remove(&linkage)) != 0) {
+#ifdef DEBUG
+ cmn_err(CE_WARN, "idmap: Failed to remove kernel module");
+#endif /* DEBUG */
+ return (i);
+ }
+
+ return (0);
+}
diff --git a/usr/src/uts/common/idmap/kidmap_priv.h b/usr/src/uts/common/idmap/kidmap_priv.h
new file mode 100644
index 0000000000..2c7b04825b
--- /dev/null
+++ b/usr/src/uts/common/idmap/kidmap_priv.h
@@ -0,0 +1,99 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Windows to Solaris Identity Mapping kernel API
+ * This header file contains private definitions.
+ */
+
+#ifndef _KIDMAP_PRIV_H
+#define _KIDMAP_PRIV_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/avl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum cache_state { CACHE_CREATED,
+ CACHE_PURGING,
+ CACHE_DESTROYING };
+
+typedef struct idmap_avl_cache {
+ avl_tree_t tree;
+ krwlock_t lock;
+ kmutex_t mutex;
+ enum cache_state state;
+ time_t purge_time;
+} idmap_avl_cache_t;
+
+typedef struct idmap_cache {
+ idmap_avl_cache_t sid;
+ idmap_avl_cache_t pid;
+} idmap_cache_t;
+
+
+void
+kidmap_cache_create(idmap_cache_t *cache);
+
+void
+kidmap_cache_delete(idmap_cache_t *cache);
+
+int
+kidmap_cache_lookupbypid(idmap_cache_t *cache, const char **sid_prefix,
+ uint32_t *rid, uid_t pid, int is_user);
+
+int
+kidmap_cache_lookupbysid(idmap_cache_t *cache, const char *sid_prefix,
+ uint32_t rid, uid_t *pid, int *is_user);
+
+void
+kidmap_cache_addbypid(idmap_cache_t *cache, const char *sid_prefix,
+ uint32_t rid, uid_t pid, int is_user, time_t ttl);
+
+void
+kidmap_cache_addbysid(idmap_cache_t *cache, const char *sid_prefix,
+ uint32_t rid, uid_t pid, int is_user, time_t ttl);
+
+int
+kidmap_start(void);
+
+int
+kidmap_stop(void);
+
+void
+kidmap_sid_prefix_store_init(void);
+
+const char *
+kidmap_find_sid_prefix(const char *sid_prefix);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _KIDMAP_PRIV_H */
diff --git a/usr/src/uts/common/os/cred.c b/usr/src/uts/common/os/cred.c
index bd215bc770..7048aa90b8 100644
--- a/usr/src/uts/common/os/cred.c
+++ b/usr/src/uts/common/os/cred.c
@@ -60,6 +60,7 @@
#include <sys/zone.h>
#include <sys/tsol/label.h>
#include <sys/sid.h>
+#include <sys/idmap.h>
typedef struct ephidmap_data {
uid_t min_uid, last_uid;
@@ -89,7 +90,7 @@ static int get_c2audit_load(void);
* Start with an invalid value for atomic increments.
*/
static ephidmap_data_t ephemeral_data = {
- MAXUID, MAXUID, MAXUID, MAXUID
+ MAXUID, IDMAP_WK__MAX_UID, MAXUID, IDMAP_WK__MAX_GID
};
static boolean_t hasephids = B_FALSE;
@@ -122,7 +123,7 @@ cred_init(void)
}
cred_cache = kmem_cache_create("cred_cache", crsize, 0,
- NULL, NULL, NULL, NULL, NULL, 0);
+ NULL, NULL, NULL, NULL, NULL, 0);
/*
* dummycr is used to copy initial state for creds.
@@ -528,7 +529,7 @@ crcmp(const cred_t *cr1, const cred_t *cr2)
cr1->cr_ngroups == cr2->cr_ngroups &&
cr1->cr_zone == cr2->cr_zone &&
bcmp(cr1->cr_groups, cr2->cr_groups,
- cr1->cr_ngroups * sizeof (gid_t)) == 0) {
+ cr1->cr_ngroups * sizeof (gid_t)) == 0) {
return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
}
return (1);
@@ -970,14 +971,16 @@ boolean_t
valid_ephemeral_uid(uid_t id)
{
membar_consumer();
- return (id > ephemeral_data.min_uid && id <= ephemeral_data.last_uid);
+ return (id < IDMAP_WK__MAX_UID ||
+ (id > ephemeral_data.min_uid && id <= ephemeral_data.last_uid));
}
boolean_t
valid_ephemeral_gid(gid_t id)
{
membar_consumer();
- return (id > ephemeral_data.min_gid && id <= ephemeral_data.last_gid);
+ return (id < IDMAP_WK__MAX_GID ||
+ (id > ephemeral_data.min_gid && id <= ephemeral_data.last_gid));
}
int
diff --git a/usr/src/uts/common/os/sid.c b/usr/src/uts/common/os/sid.c
index d5bef7def5..0da71f3cdf 100644
--- a/usr/src/uts/common/os/sid.c
+++ b/usr/src/uts/common/os/sid.c
@@ -38,6 +38,10 @@
#include <sys/sid.h>
#include <sys/sysmacros.h>
#include <sys/systm.h>
+#include <sys/kidmap.h>
+#include <sys/idmap.h>
+
+#define KSIDLIST_MEM(n) (sizeof (ksidlist_t) + ((n) - 1) * sizeof (ksid_t))
static kmutex_t sid_lock;
static avl_tree_t sid_tree;
@@ -185,16 +189,30 @@ ksid_getrid(ksid_t *ks)
}
int
-ksid_lookup(uid_t id, ksid_t *res)
+ksid_lookupbyuid(uid_t id, ksid_t *res)
{
- uid_t tmp;
+ const char *sid_prefix;
- if (idmap_call_byid(id, res) == -1)
+ if (kidmap_getsidbyuid(id, &sid_prefix, &res->ks_rid) != IDMAP_SUCCESS)
return (-1);
- tmp = idmap_call_bysid(res);
- if (tmp != id)
- cmn_err(CE_WARN, "The idmapper has gone bonkers");
+ res->ks_domain = ksid_lookupdomain(sid_prefix);
+
+ res->ks_id = id;
+
+ return (0);
+}
+
+int
+ksid_lookupbygid(gid_t id, ksid_t *res)
+{
+ const char *sid_prefix;
+
+ if (kidmap_getsidbygid(id, &sid_prefix, &res->ks_rid) != IDMAP_SUCCESS)
+ return (-1);
+
+ res->ks_domain = ksid_lookupdomain(sid_prefix);
+
res->ks_id = id;
return (0);
@@ -376,7 +394,7 @@ kcrsid_gidstosids(int ngrp, gid_t *grp)
for (i = 0; i < ngrp; i++) {
if (grp[i] > MAXUID) {
list->ksl_neid++;
- if (ksid_lookup(grp[i], &list->ksl_sids[i]) != 0) {
+ if (ksid_lookupbygid(grp[i], &list->ksl_sids[i]) != 0) {
while (--i >= 0)
ksid_rele(&list->ksl_sids[i]);
cnt = 0;
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index 184473fe4d..0a214abc46 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -257,6 +257,7 @@ CHKHDRS= \
ia.h \
iapriocntl.h \
id32.h \
+ idmap.h \
ieeefp.h \
id_space.h \
instance.h \
@@ -281,6 +282,7 @@ CHKHDRS= \
kcpc.h \
kdi.h \
kdi_impl.h \
+ kidmap.h \
klwp.h \
kmdb.h \
kmem.h \
diff --git a/usr/src/uts/common/sys/idmap.h b/usr/src/uts/common/sys/idmap.h
new file mode 100644
index 0000000000..b6bd80f393
--- /dev/null
+++ b/usr/src/uts/common/sys/idmap.h
@@ -0,0 +1,74 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_IDMAP_H
+#define _SYS_IDMAP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Idmap status codes */
+#define IDMAP_SUCCESS 0
+#define IDMAP_NEXT 1
+#define IDMAP_ERR_OTHER -10000
+#define IDMAP_ERR_INTERNAL -9999
+#define IDMAP_ERR_MEMORY -9998
+#define IDMAP_ERR_NORESULT -9997
+#define IDMAP_ERR_NOTUSER -9996
+#define IDMAP_ERR_NOTGROUP -9995
+#define IDMAP_ERR_NOTSUPPORTED -9994
+#define IDMAP_ERR_W2U_NAMERULE -9993
+#define IDMAP_ERR_U2W_NAMERULE -9992
+#define IDMAP_ERR_CACHE -9991
+#define IDMAP_ERR_DB -9990
+#define IDMAP_ERR_ARG -9989
+#define IDMAP_ERR_SID -9988
+#define IDMAP_ERR_IDTYPE -9987
+#define IDMAP_ERR_RPC_HANDLE -9986
+#define IDMAP_ERR_RPC -9985
+#define IDMAP_ERR_CLIENT_HANDLE -9984
+#define IDMAP_ERR_BUSY -9983
+#define IDMAP_ERR_PERMISSION_DENIED -9982
+#define IDMAP_ERR_NOMAPPING -9981
+#define IDMAP_ERR_NEW_ID_ALLOC_REQD -9980
+#define IDMAP_ERR_DOMAIN -9979
+#define IDMAP_ERR_SECURITY -9978
+#define IDMAP_ERR_NOTFOUND -9977
+#define IDMAP_ERR_DOMAIN_NOTFOUND -9976
+#define IDMAP_ERR_UPDATE_NOTALLOWED -9975
+#define IDMAP_ERR_CFG -9974
+#define IDMAP_ERR_CFG_CHANGE -9973
+#define IDMAP_ERR_NOTMAPPED_WELLKNOWN -9972
+#define IDMAP_ERR_RETRIABLE_NET_ERR -9971
+
+/* Reserved GIDs for some well-known SIDs */
+#define IDMAP_WK_LOCAL_SYSTEM_GID 2147483648U
+#define IDMAP_WK_CREATOR_GROUP_GID 2147483649U
+#define IDMAP_WK__MAX_GID 2147483649U
+
+/* Reserved UIDs for some well-known SIDs */
+#define IDMAP_WK_CREATOR_OWNER_UID 2147483648U
+#define IDMAP_WK__MAX_UID 2147483648U
+
+#endif /* _SYS_IDMAP_H */
diff --git a/usr/src/uts/common/sys/kidmap.h b/usr/src/uts/common/sys/kidmap.h
new file mode 100644
index 0000000000..36fb0e8143
--- /dev/null
+++ b/usr/src/uts/common/sys/kidmap.h
@@ -0,0 +1,158 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Windows to Solaris Identity Mapping kernel API
+ * This header defines an API to map Windows SIDs to
+ * Solaris UID and GIDs and versa visa.
+ */
+
+#ifndef _SYS_KIDMAP_H
+#define _SYS_KIDMAP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/idmap.h>
+#include <sys/door.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Opaque get handle */
+typedef struct idmap_get_handle idmap_get_handle_t;
+
+/* Return status */
+typedef int32_t idmap_stat;
+
+/*
+ * In all the routines a Windows SID is handled as a
+ * string SID prefix plus a RID. For example
+ *
+ * S-1-5-5-12-34-568 will be passed as SID prefix
+ * S-1-5-5-12-34 and RID 568
+ *
+ * Certain routines returns pointers to a SID prefix string.
+ * These strings are stored internally and should not be modified
+ * or freed.
+ */
+
+
+/*
+ * The following routines are simple get ID mapping routines.
+ */
+
+
+idmap_stat
+kidmap_getuidbysid(const char *sid_prefix, uint32_t rid, uid_t *uid);
+
+idmap_stat
+kidmap_getgidbysid(const char *sid_prefix, uint32_t rid, gid_t *gid);
+
+idmap_stat
+kidmap_getpidbysid(const char *sid_prefix, uint32_t rid, uid_t *pid,
+ int *is_user);
+
+idmap_stat
+kidmap_getsidbyuid(uid_t uid, const char **sid_prefix, uint32_t *rid);
+
+idmap_stat
+kidmap_getsidbygid(gid_t gid, const char **sid_prefix, uint32_t *rid);
+
+
+
+/*
+ * The following routines provide a batch interface for mapping IDs.
+ */
+
+/*
+ * Create a batch "get mapping" handle for batch mappings.
+ */
+idmap_get_handle_t *
+kidmap_get_create(void);
+
+/*
+ * These routines queue the request to the "get mapping" handle
+ */
+
+idmap_stat
+kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ uid_t *uid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ gid_t *gid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ uid_t *pid, int *is_user, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat);
+
+/*
+ * Process the queued "get mapping" requests. The results (i.e.
+ * status and identity) will be available in the data areas
+ * provided by individual requests.
+ */
+idmap_stat
+kidmap_get_mappings(idmap_get_handle_t *get_handle);
+
+/*
+ * Destroy the "get mapping" handle
+ */
+void
+kidmap_get_destroy(idmap_get_handle_t *get_handle);
+
+/*
+ * Functions that do the hard part of door registration/unregistration
+ * for the idmap_reg()/idmap_unreg() syscalls
+ */
+int idmap_reg_dh(door_handle_t dh);
+int idmap_unreg_dh(door_handle_t dh);
+
+/*
+ * Functions needed by allocids() to ensure only the daemon that owns
+ * the door gets ephemeral IDS
+ */
+typedef struct idmap_reg idmap_reg_t;
+
+void idmap_get_door(idmap_reg_t **state, door_handle_t *dh);
+void idmap_release_door(idmap_reg_t *idmp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_KIDMAP_H */
diff --git a/usr/src/uts/common/sys/sid.h b/usr/src/uts/common/sys/sid.h
index 8a2605f484..9d68191eb6 100644
--- a/usr/src/uts/common/sys/sid.h
+++ b/usr/src/uts/common/sys/sid.h
@@ -51,20 +51,6 @@ extern "C" {
#define SIDSYS_SID2ID 0
#define SIDSYS_ID2SID 1
-typedef struct domsid {
- uint_t ds_rid;
- char ds_dom[1];
-} domsid_t;
-
-typedef struct sidmap_call {
- int sc_type;
- union sc_val_u {
- uid_t sc_id;
- domsid_t sc_sid;
- } sc_val;
-} sidmap_call_t;
-
-
#ifdef _KERNEL
/* Domains are stored in AVL trees so we can share them among SIDs */
typedef struct ksiddomain {
@@ -100,8 +86,6 @@ typedef struct ksidlist {
ksid_t ksl_sids[1]; /* Allocate ksl_nsid times */
} ksidlist_t;
-#define KSIDLIST_MEM(n) (sizeof (ksidlist_t) + ((n) - 1) * sizeof (ksid_t))
-
typedef struct credsid {
uint_t kr_ref; /* Reference count */
ksid_t kr_sidx[KSID_COUNT]; /* User, group, default owner */
@@ -111,7 +95,8 @@ typedef struct credsid {
const char *ksid_getdomain(ksid_t *);
uint_t ksid_getrid(ksid_t *);
-int ksid_lookup(uid_t, ksid_t *);
+int ksid_lookupbyuid(uid_t, ksid_t *);
+int ksid_lookupbygid(gid_t, ksid_t *);
void ksid_rele(ksid_t *);
credsid_t *kcrsid_alloc(void);
@@ -132,9 +117,6 @@ ksiddomain_t *ksid_lookupdomain(const char *);
ksidlist_t *kcrsid_gidstosids(int, gid_t *);
-int idmap_call_byid(uid_t, ksid_t *);
-uid_t idmap_call_bysid(ksid_t *);
-
#else
int allocids(int, int, uid_t *, int, gid_t *);
diff --git a/usr/src/uts/common/syscall/gid.c b/usr/src/uts/common/syscall/gid.c
index 388225b600..4ea9660cc3 100644
--- a/usr/src/uts/common/syscall/gid.c
+++ b/usr/src/uts/common/syscall/gid.c
@@ -53,7 +53,7 @@ setgid(gid_t gid)
return (set_errno(EINVAL));
if (gid > MAXUID) {
- if (ksid_lookup(gid, &ksid) != 0)
+ if (ksid_lookupbygid(gid, &ksid) != 0)
return (set_errno(EINVAL));
ksp = &ksid;
} else {
@@ -137,7 +137,7 @@ setegid(gid_t gid)
return (set_errno(EINVAL));
if (gid > MAXUID) {
- if (ksid_lookup(gid, &ksid) != 0)
+ if (ksid_lookupbygid(gid, &ksid) != 0)
return (set_errno(EINVAL));
ksp = &ksid;
} else {
@@ -205,7 +205,7 @@ setregid(gid_t rgid, gid_t egid)
return (set_errno(EINVAL));
if (egid != -1 && egid > MAXUID) {
- if (ksid_lookup(egid, &ksid) != 0)
+ if (ksid_lookupbygid(egid, &ksid) != 0)
return (set_errno(EINVAL));
ksp = &ksid;
} else {
diff --git a/usr/src/uts/common/syscall/sidsys.c b/usr/src/uts/common/syscall/sidsys.c
index bcb749cadc..9e51fe170c 100644
--- a/usr/src/uts/common/syscall/sidsys.c
+++ b/usr/src/uts/common/syscall/sidsys.c
@@ -36,148 +36,53 @@
#include <sys/systm.h>
#include <sys/policy.h>
#include <sys/door.h>
+#include <sys/kidmap.h>
+#include <sys/proc.h>
-static kmutex_t idmap_mutex;
-
-typedef struct idmap_reg {
- door_handle_t idmap_door;
- int idmap_flags;
- int idmap_ref;
-} idmap_reg_t;
-
-static idmap_reg_t *idmap_ptr;
-
-static int idmap_unreg_dh(door_handle_t);
-
-static void
-idmap_freeone(idmap_reg_t *p)
-{
- ASSERT(p->idmap_ref == 0);
- ASSERT(MUTEX_HELD(&idmap_mutex));
-
- door_ki_rele(p->idmap_door);
- if (idmap_ptr == p)
- idmap_ptr = NULL;
-
- kmem_free(p, sizeof (*p));
-}
-
-static int
-idmap_do_call(sidmap_call_t *callp, size_t callsz, void **resp, size_t *respsz)
-{
- door_arg_t da;
- idmap_reg_t *p;
- int ret;
- int dres;
-
- mutex_enter(&idmap_mutex);
- p = idmap_ptr;
- if (p != NULL) {
- p->idmap_ref++;
- } else {
- mutex_exit(&idmap_mutex);
- return (-1);
- }
- mutex_exit(&idmap_mutex);
-
- da.data_ptr = (char *)callp;
- da.data_size = callsz;
- da.desc_ptr = NULL;
- da.desc_num = 0;
- da.rbuf = *resp;
- da.rsize = *respsz;
-
- while ((dres = door_ki_upcall(p->idmap_door, &da)) != 0) {
- switch (dres) {
- case EINTR:
- case EAGAIN:
- delay(1);
- continue;
- case EINVAL:
- case EBADF:
- (void) idmap_unreg_dh(p->idmap_door);
- /* FALLTHROUGH */
- default:
- ret = -1;
- goto out;
- }
- }
- *resp = da.rbuf;
- *respsz = da.rsize;
- ret = 0;
-out:
- mutex_enter(&idmap_mutex);
- if (--p->idmap_ref == 0)
- idmap_freeone(p);
- mutex_exit(&idmap_mutex);
- return (ret);
-}
-
-/*
- * Current code only attempts to map ids to sids.
- */
-int
-idmap_call_byid(uid_t id, ksid_t *ksid)
+static uint64_t
+allocids(int flag, int nuids, int ngids)
{
- sidmap_call_t call;
- domsid_t res, *resp = &res;
- size_t respsz = sizeof (res);
-
- call.sc_type = SIDSYS_ID2SID;
- call.sc_val.sc_id = id;
-
- if (idmap_do_call(&call, sizeof (call), (void **)&resp, &respsz) != 0)
- return (-1);
-
- ksid->ks_domain = ksid_lookupdomain(resp->ds_dom);
- ksid->ks_rid = resp->ds_rid;
+ rval_t r;
+ uid_t su = 0;
+ gid_t sg = 0;
+ struct door_info di;
+ door_handle_t dh;
+ idmap_reg_t *reg;
+ int err;
- /* Larger SID return value; this usually happens */
- if (resp != &res)
- kmem_free(resp, respsz);
+ idmap_get_door(&reg, &dh);
- return (0);
-}
+ if (reg == NULL || dh == NULL)
+ return (set_errno(EPERM));
-uid_t
-idmap_call_bysid(ksid_t *ksid)
-{
- ksiddomain_t *domp = ksid->ks_domain;
- sidmap_call_t *callp;
- uid_t res = (uid_t)-1;
- uid_t *resp = &res;
- size_t callsz;
- size_t respsz = sizeof (res);
+ if ((err = door_ki_info(dh, &di)) != 0)
+ return (set_errno(err));
- callsz = sizeof (sidmap_call_t) + domp->kd_len;
+ if (curproc->p_pid != di.di_target)
+ return (set_errno(EPERM));
- callp = kmem_alloc(callsz, KM_SLEEP);
- callp->sc_type = SIDSYS_SID2ID;
- bcopy(domp->kd_name, callp->sc_val.sc_sid.ds_dom, domp->kd_len);
- callp->sc_val.sc_sid.ds_rid = ksid->ks_rid;
+ idmap_release_door(reg);
- if (idmap_do_call(callp, callsz, (void **)&resp, &respsz) != 0)
- goto out;
+ if (nuids < 0 || ngids < 0)
+ return (set_errno(EINVAL));
- /* Should never happen; the original buffer should be large enough */
- if (resp != &res) {
- kmem_free(resp, respsz);
- goto out;
- }
+ if (flag != 0 || nuids > 0)
+ err = eph_uid_alloc(flag, &su, nuids);
+ if (err == 0 && (flag != 0 || ngids > 0))
+ err = eph_gid_alloc(flag, &sg, ngids);
- if (respsz != sizeof (uid_t))
- res = (uid_t)-1;
+ if (err != 0)
+ return (set_errno(EOVERFLOW));
-out:
- kmem_free(callp, callsz);
- return (res);
+ r.r_val1 = su;
+ r.r_val2 = sg;
+ return (r.r_vals);
}
static int
idmap_reg(int did)
{
door_handle_t dh;
- idmap_reg_t *idmp;
int err;
if ((err = secpolicy_idmap(CRED())) != 0)
@@ -188,39 +93,9 @@ idmap_reg(int did)
if (dh == NULL)
return (set_errno(EBADF));
- idmp = kmem_alloc(sizeof (*idmp), KM_SLEEP);
-
- idmp->idmap_door = dh;
- mutex_enter(&idmap_mutex);
- if (idmap_ptr != NULL) {
- if (--idmap_ptr->idmap_ref == 0)
- idmap_freeone(idmap_ptr);
- }
- idmp->idmap_flags = 0;
- idmp->idmap_ref = 1;
- idmap_ptr = idmp;
- mutex_exit(&idmap_mutex);
- return (0);
-}
-
-static int
-idmap_unreg_dh(door_handle_t dh)
-{
- mutex_enter(&idmap_mutex);
- if (idmap_ptr == NULL || idmap_ptr->idmap_door != dh) {
- mutex_exit(&idmap_mutex);
- return (EINVAL);
- }
+ err = idmap_reg_dh(dh);
- if (idmap_ptr->idmap_flags != 0) {
- mutex_exit(&idmap_mutex);
- return (EAGAIN);
- }
- idmap_ptr->idmap_flags = 1;
- if (--idmap_ptr->idmap_ref == 0)
- idmap_freeone(idmap_ptr);
- mutex_exit(&idmap_mutex);
- return (0);
+ return (err);
}
static int
@@ -240,49 +115,6 @@ idmap_unreg(int did)
return (0);
}
-static boolean_t
-its_my_door(void)
-{
- mutex_enter(&idmap_mutex);
- if (idmap_ptr != NULL) {
- struct door_info info;
- int err = door_ki_info(idmap_ptr->idmap_door, &info);
- if (err == 0 && info.di_target == curproc->p_pid) {
- mutex_exit(&idmap_mutex);
- return (B_TRUE);
- }
- }
- mutex_exit(&idmap_mutex);
- return (B_FALSE);
-}
-
-static uint64_t
-allocids(int flag, int nuids, int ngids)
-{
- rval_t r;
- uid_t su = 0;
- gid_t sg = 0;
- int err;
-
- if (!its_my_door())
- return (set_errno(EPERM));
-
- if (nuids < 0 || ngids < 0)
- return (set_errno(EINVAL));
-
- if (flag != 0 || nuids > 0)
- err = eph_uid_alloc(flag, &su, nuids);
- if (err == 0 && (flag != 0 || ngids > 0))
- err = eph_gid_alloc(flag, &sg, ngids);
-
- if (err != 0)
- return (set_errno(EOVERFLOW));
-
- r.r_val1 = su;
- r.r_val2 = sg;
- return (r.r_vals);
-}
-
uint64_t
sidsys(int op, int flag, int nuids, int ngids)
{
diff --git a/usr/src/uts/common/syscall/uid.c b/usr/src/uts/common/syscall/uid.c
index 24e1e92f82..ef96933ba3 100644
--- a/usr/src/uts/common/syscall/uid.c
+++ b/usr/src/uts/common/syscall/uid.c
@@ -59,7 +59,7 @@ setuid(uid_t uid)
return (set_errno(EINVAL));
if (uid > MAXUID) {
- if (ksid_lookup(uid, &ksid) != 0)
+ if (ksid_lookupbyuid(uid, &ksid) != 0)
return (set_errno(EINVAL));
ksp = &ksid;
} else {
@@ -178,7 +178,7 @@ seteuid(uid_t uid)
return (set_errno(EINVAL));
if (uid > MAXUID) {
- if (ksid_lookup(uid, &ksid) != 0)
+ if (ksid_lookupbyuid(uid, &ksid) != 0)
return (set_errno(EINVAL));
ksp = &ksid;
} else {
@@ -252,7 +252,7 @@ setreuid(uid_t ruid, uid_t euid)
return (set_errno(EINVAL));
if (euid != -1 && euid > MAXUID) {
- if (ksid_lookup(euid, &ksid) != 0)
+ if (ksid_lookupbyuid(euid, &ksid) != 0)
return (set_errno(EINVAL));
ksp = &ksid;
} else {
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index b2b3c987f4..02fb5eb12e 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -518,6 +518,7 @@ MISC_KMODS += ibcm
MISC_KMODS += ibdm
MISC_KMODS += ibmf
MISC_KMODS += ibtl
+MISC_KMODS += idmap
MISC_KMODS += ipc
MISC_KMODS += kbtrans
MISC_KMODS += kcf
diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s
index 7528c60faf..2d16849c3d 100644
--- a/usr/src/uts/intel/ia32/ml/modstubs.s
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s
@@ -884,6 +884,31 @@ fcnname/**/_info: \
#endif
/*
+ * Stubs for idmap
+ */
+#ifndef IDMAP_MODULE
+ MODULE(idmap,misc);
+ STUB(idmap,kidmap_batch_getgidbysid,nomod_zero);
+ STUB(idmap,kidmap_batch_getpidbysid,nomod_zero);
+ STUB(idmap,kidmap_batch_getsidbygid,nomod_zero);
+ STUB(idmap,kidmap_batch_getsidbyuid,nomod_zero);
+ STUB(idmap,kidmap_batch_getuidbysid,nomod_zero);
+ STUB(idmap,kidmap_get_create,nomod_zero);
+ STUB(idmap,kidmap_get_destroy,nomod_zero);
+ STUB(idmap,kidmap_get_mappings,nomod_zero);
+ STUB(idmap,kidmap_getgidbysid,nomod_zero);
+ STUB(idmap,kidmap_getpidbysid,nomod_zero);
+ STUB(idmap,kidmap_getsidbygid,nomod_zero);
+ STUB(idmap,kidmap_getsidbyuid,nomod_zero);
+ STUB(idmap,kidmap_getuidbysid,nomod_zero);
+ STUB(idmap,idmap_get_door,nomod_einval);
+ STUB(idmap,idmap_unreg_dh,nomod_einval);
+ STUB(idmap,idmap_reg_dh,nomod_einval);
+ STUB(idmap,idmap_release_door,nomod_einval);
+ END_MODULE(idmap);
+#endif
+
+/*
* Stubs for auditing.
*/
#ifndef C2AUDIT_MODULE
diff --git a/usr/src/uts/intel/idmap/Makefile b/usr/src/uts/intel/idmap/Makefile
new file mode 100755
index 0000000000..ad4e11de72
--- /dev/null
+++ b/usr/src/uts/intel/idmap/Makefile
@@ -0,0 +1,97 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the idmap (Identity mapping between
+# Solaris and Windows) kernel module.
+#
+# Intel implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = idmap
+OBJECTS = $(IDMAP_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(IDMAP_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+# Module dependencies
+#
+LDFLAGS += -dy -N"sys/doorfs" -N"strmod/rpcmod"
+
+#
+# Include dependencies
+#
+INC_PATH += -I$(SRC)/head/rpcsvc
+
+#
+# Lint warnings turned off (for rpcgen-generated code)
+#
+LINTFLAGS += -erroff=E_FUNC_VAR_UNUSED
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+CLEANFILES += $(MODSTUBS_O)
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 3ca98f33af..fea69f77f7 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -377,6 +377,7 @@ MISC_KMODS += ibcm
MISC_KMODS += ibdm
MISC_KMODS += ibmf
MISC_KMODS += ibtl
+MISC_KMODS += idmap
MISC_KMODS += hook
MISC_KMODS += neti
MISC_KMODS += ctf
diff --git a/usr/src/uts/sparc/idmap/Makefile b/usr/src/uts/sparc/idmap/Makefile
new file mode 100755
index 0000000000..a476b3afc6
--- /dev/null
+++ b/usr/src/uts/sparc/idmap/Makefile
@@ -0,0 +1,98 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the idmap (Identity mapping between
+# Solaris and Windows) kernel module.
+#
+# Sparc implementation architecture dependent
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = idmap
+OBJECTS = $(IDMAP_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(IDMAP_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+# Module dependencies
+#
+LDFLAGS += -dy -N"sys/doorfs" -N"strmod/rpcmod"
+
+#
+# Include dependencies
+#
+INC_PATH += -I$(SRC)/head/rpcsvc
+
+#
+# Lint warnings turned off (for rpcgen-generated code)
+#
+LINTFLAGS += -erroff=E_FUNC_VAR_UNUSED
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+CLEANFILES += $(MODSTUBS_O)
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s
index 9cc218756d..5eade06f7b 100644
--- a/usr/src/uts/sparc/ml/modstubs.s
+++ b/usr/src/uts/sparc/ml/modstubs.s
@@ -807,6 +807,31 @@ stubs_base:
#endif
/*
+ * Stubs for idmap
+ */
+#ifndef IDMAP_MODULE
+ MODULE(idmap,misc);
+ STUB(idmap,kidmap_batch_getgidbysid,nomod_zero);
+ STUB(idmap,kidmap_batch_getpidbysid,nomod_zero);
+ STUB(idmap,kidmap_batch_getsidbygid,nomod_zero);
+ STUB(idmap,kidmap_batch_getsidbyuid,nomod_zero);
+ STUB(idmap,kidmap_batch_getuidbysid,nomod_zero);
+ STUB(idmap,kidmap_get_create,nomod_zero);
+ STUB(idmap,kidmap_get_destroy,nomod_zero);
+ STUB(idmap,kidmap_get_mappings,nomod_zero);
+ STUB(idmap,kidmap_getgidbysid,nomod_zero);
+ STUB(idmap,kidmap_getpidbysid,nomod_zero);
+ STUB(idmap,kidmap_getsidbygid,nomod_zero);
+ STUB(idmap,kidmap_getsidbyuid,nomod_zero);
+ STUB(idmap,kidmap_getuidbysid,nomod_zero);
+ STUB(idmap,idmap_get_door,nomod_einval);
+ STUB(idmap,idmap_unreg_dh,nomod_einval);
+ STUB(idmap,idmap_reg_dh,nomod_einval);
+ STUB(idmap,idmap_release_door,nomod_einval);
+ END_MODULE(idmap);
+#endif
+
+/*
* Stubs for dma routines. dmaga.c
* (These are only needed for cross-checks, not autoloading)
*/