diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/Makefile.lint | 2 | ||||
-rw-r--r-- | usr/src/Targetdirs | 4 | ||||
-rw-r--r-- | usr/src/cmd/Makefile | 4 | ||||
-rw-r--r-- | usr/src/cmd/idmap/Makefile | 48 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmap/Makefile | 72 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmap/idmap.c | 2109 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmap/idmap_engine.c | 576 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmap/idmap_engine.h | 68 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/Makefile | 109 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/adutils.c | 1493 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/adutils.h | 182 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/dbutils.c | 2665 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/idmap.xml | 118 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/idmap_config.c | 389 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/idmap_config.h | 72 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/idmapd.c | 361 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/idmapd.h | 185 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/init.c | 151 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/mapfile-intf | 33 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/rpc_svc.c | 189 | ||||
-rw-r--r-- | usr/src/cmd/idmap/idmapd/server.c | 726 | ||||
-rw-r--r-- | usr/src/cmd/idmap/req.flg | 30 | ||||
-rw-r--r-- | usr/src/cmd/rpcsvc/net_files/rpc | 10 | ||||
-rw-r--r-- | usr/src/cmd/sqlite/Makefile | 69 | ||||
-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/Makefile | 31 | ||||
-rw-r--r-- | usr/src/cmd/svc/configd/backend.c | 17 | ||||
-rw-r--r-- | usr/src/head/rpcsvc/idmap_prot.x | 160 | ||||
-rw-r--r-- | usr/src/lib/Makefile | 6 | ||||
-rw-r--r-- | usr/src/lib/libc/port/llib-lc | 1 | ||||
-rw-r--r-- | usr/src/lib/libidmap/Makefile | 65 | ||||
-rw-r--r-- | usr/src/lib/libidmap/Makefile.com | 64 | ||||
-rw-r--r-- | usr/src/lib/libidmap/amd64/Makefile | 31 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/idmap.h | 110 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/idmap_api.c | 1689 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/idmap_impl.h | 113 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/idmap_priv.h | 143 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/llib-lidmap | 31 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/mapfile-vers | 74 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/utils.c | 141 | ||||
-rw-r--r-- | usr/src/lib/libidmap/i386/Makefile | 30 | ||||
-rw-r--r-- | usr/src/lib/libidmap/sparc/Makefile | 30 | ||||
-rw-r--r-- | usr/src/lib/libidmap/sparcv9/Makefile | 31 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/auth_attr.txt | 4 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/help/auths/IdmapRules.html | 40 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/help/auths/Makefile | 5 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/help/auths/SmfIdmapStates.html | 40 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/help/auths/SmfValueIdmap.html | 40 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/help/profiles/Makefile | 4 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/help/profiles/RtIdmapMngmnt.html | 40 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/help/profiles/RtIdmapNameRulesMngmnt.html | 41 | ||||
-rw-r--r-- | usr/src/lib/libsecdb/prof_attr.txt | 2 | ||||
-rw-r--r-- | usr/src/lib/libsqlite/Makefile | 64 | ||||
-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/Makefile | 32 | ||||
-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/Makefile | 32 | ||||
-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_com | 5 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWckr/prototype_i386 | 2 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWckr/prototype_sparc | 1 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWcsl/prototype_com | 1 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWcsl/prototype_i386 | 1 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWcsl/prototype_sparc | 1 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWcsr/prototype_com | 2 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWcsu/prototype_com | 7 | ||||
-rw-r--r-- | usr/src/pkgdefs/etc/exception_list_i386 | 21 | ||||
-rw-r--r-- | usr/src/pkgdefs/etc/exception_list_sparc | 21 | ||||
-rw-r--r-- | usr/src/tools/abi/etc/exceptions | 3 | ||||
-rw-r--r-- | usr/src/tools/findunref/exception_list | 3 | ||||
-rw-r--r-- | usr/src/uts/Makefile | 3 | ||||
-rw-r--r-- | usr/src/uts/common/Makefile.files | 5 | ||||
-rw-r--r-- | usr/src/uts/common/Makefile.rules | 7 | ||||
-rwxr-xr-x | usr/src/uts/common/idmap/Makefile | 61 | ||||
-rw-r--r-- | usr/src/uts/common/idmap/idmap_cache.c | 474 | ||||
-rw-r--r-- | usr/src/uts/common/idmap/idmap_kapi.c | 1318 | ||||
-rw-r--r-- | usr/src/uts/common/idmap/idmap_mod.c | 103 | ||||
-rw-r--r-- | usr/src/uts/common/idmap/kidmap_priv.h | 99 | ||||
-rw-r--r-- | usr/src/uts/common/os/cred.c | 13 | ||||
-rw-r--r-- | usr/src/uts/common/os/sid.c | 32 | ||||
-rw-r--r-- | usr/src/uts/common/sys/Makefile | 2 | ||||
-rw-r--r-- | usr/src/uts/common/sys/idmap.h | 74 | ||||
-rw-r--r-- | usr/src/uts/common/sys/kidmap.h | 158 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sid.h | 22 | ||||
-rw-r--r-- | usr/src/uts/common/syscall/gid.c | 6 | ||||
-rw-r--r-- | usr/src/uts/common/syscall/sidsys.c | 232 | ||||
-rw-r--r-- | usr/src/uts/common/syscall/uid.c | 6 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.intel.shared | 1 | ||||
-rw-r--r-- | usr/src/uts/intel/ia32/ml/modstubs.s | 25 | ||||
-rwxr-xr-x | usr/src/uts/intel/idmap/Makefile | 97 | ||||
-rw-r--r-- | usr/src/uts/sparc/Makefile.sparc.shared | 1 | ||||
-rwxr-xr-x | usr/src/uts/sparc/idmap/Makefile | 98 | ||||
-rw-r--r-- | usr/src/uts/sparc/ml/modstubs.s | 25 |
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(¶m, 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> +</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> +</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> +</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(®, &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(¶ms) != 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(®, &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) */ |