diff options
-rw-r--r-- | source4/Makefile | 1 | ||||
-rw-r--r-- | source4/build/m4/check_path.m4 | 19 | ||||
-rw-r--r-- | source4/dynconfig/config.mk | 3 | ||||
-rw-r--r-- | source4/dynconfig/dynconfig.c | 3 | ||||
-rw-r--r-- | source4/dynconfig/dynconfig.h | 1 | ||||
-rw-r--r-- | source4/headermap.txt | 1 | ||||
-rw-r--r-- | source4/librpc/config.mk | 2 | ||||
-rw-r--r-- | source4/librpc/idl/ntp_signd.idl | 14 | ||||
-rw-r--r-- | source4/ntp_signd/ntp_signd.c | 151 | ||||
-rw-r--r-- | source4/param/loadparm.c | 7 | ||||
-rw-r--r-- | source4/param/param.h | 2 |
11 files changed, 180 insertions, 24 deletions
diff --git a/source4/Makefile b/source4/Makefile index 14d0fe3b20..b7d5206868 100644 --- a/source4/Makefile +++ b/source4/Makefile @@ -167,6 +167,7 @@ showlayout:: @echo ' torturedir: $(TORTUREDIR)' @echo ' datadir: $(datadir)' @echo ' winbindd_socket_dir: $(winbindd_socket_dir)' + @echo ' ntp_signd_socket_dir: $(ntp_signd_socket_dir)' showflags:: @echo ' srcdir = $(srcdir)' diff --git a/source4/build/m4/check_path.m4 b/source4/build/m4/check_path.m4 index 08a858ebb2..c0b81f1a8d 100644 --- a/source4/build/m4/check_path.m4 +++ b/source4/build/m4/check_path.m4 @@ -20,6 +20,7 @@ piddir="${localstatedir}/run" privatedir="\${prefix}/private" modulesdir="\${prefix}/modules" winbindd_socket_dir="${localstatedir}/run/winbind_pipe" +ntp_signd_socket_dir="${localstatedir}/run/ntp_signd" AC_ARG_WITH(fhs, [ --with-fhs Use FHS-compliant paths (default=no)], @@ -31,6 +32,7 @@ AC_ARG_WITH(fhs, modulesdir="${libdir}/samba" datadir="${datadir}/samba" includedir="${includedir}/samba-4.0" + ntp_signd_socket_dir="${localstatedir}/run/samba/ntp_signd" winbindd_socket_dir="${localstatedir}/run/samba/winbind_pipe" ) @@ -67,6 +69,22 @@ AC_ARG_WITH(winbindd-socket-dir, esac]) ################################################# +# set where the NTP signing deamon socket should be put +AC_ARG_WITH(ntp-signd-socket-dir, +[ --with-ntp-signd-socket-dir=DIR Where to put the NTP signing deamon socket ($ac_default_prefix/run/ntp_signd)], +[ case "$withval" in + yes|no) + # + # Just in case anybody calls it without argument + # + AC_MSG_WARN([--with-ntp-signd-socketdir called without argument - will use default]) + ;; + * ) + ntp_signd_socket_dir="$withval" + ;; + esac]) + +################################################# # set lock directory location AC_ARG_WITH(lockdir, [ --with-lockdir=DIR Where to put lock files ($ac_default_prefix/var/locks)], @@ -122,6 +140,7 @@ AC_SUBST(privatedir) AC_SUBST(bindir) AC_SUBST(sbindir) AC_SUBST(winbindd_socket_dir) +AC_SUBST(ntp_signd_socket_dir) AC_SUBST(modulesdir) ################################################# diff --git a/source4/dynconfig/config.mk b/source4/dynconfig/config.mk index 5f2887f8b6..a353ba1214 100644 --- a/source4/dynconfig/config.mk +++ b/source4/dynconfig/config.mk @@ -19,5 +19,6 @@ $(dynconfigsrcdir)/dynconfig.o: CFLAGS+=-DCONFIGFILE=\"$(CONFIGFILE)\" -DBINDIR= -DPRIVATE_DIR=\"$(privatedir)\" \ -DMODULESDIR=\"$(modulesdir)\" -DJSDIR=\"$(JSDIR)\" \ -DTORTUREDIR=\"$(TORTUREDIR)\" \ - -DSETUPDIR=\"$(SETUPDIR)\" -DWINBINDD_SOCKET_DIR=\"$(winbindd_socket_dir)\" + -DSETUPDIR=\"$(SETUPDIR)\" -DWINBINDD_SOCKET_DIR=\"$(winbindd_socket_dir)\" \ + -DNTP_SIGND_SOCKET_DIR=\"$(ntp_signd_socket_dir)\" diff --git a/source4/dynconfig/dynconfig.c b/source4/dynconfig/dynconfig.c index 6dbbf872d9..ef5c40d698 100644 --- a/source4/dynconfig/dynconfig.c +++ b/source4/dynconfig/dynconfig.c @@ -84,3 +84,6 @@ _PUBLIC_ const char *dyn_JSDIR = JSDIR; /** Where to find the winbindd socket */ _PUBLIC_ const char *dyn_WINBINDD_SOCKET_DIR = WINBINDD_SOCKET_DIR; + +/** Where to find the NTP signing deamon socket */ +_PUBLIC_ const char *dyn_NTP_SIGND_SOCKET_DIR = NTP_SIGND_SOCKET_DIR; diff --git a/source4/dynconfig/dynconfig.h b/source4/dynconfig/dynconfig.h index ac54db63d6..e77c13bab3 100644 --- a/source4/dynconfig/dynconfig.h +++ b/source4/dynconfig/dynconfig.h @@ -38,3 +38,4 @@ extern const char *dyn_SWATDIR; extern const char *dyn_JSDIR; extern const char *dyn_SETUPDIR; extern const char *dyn_WINBINDD_SOCKET_DIR; +extern const char *dyn_NTP_SIGND_SOCKET_DIR; diff --git a/source4/headermap.txt b/source4/headermap.txt index 4949710aab..e2bbb167ed 100644 --- a/source4/headermap.txt +++ b/source4/headermap.txt @@ -48,7 +48,6 @@ lib/torture/torture.h: torture.h libcli/libcli.h: client.h librpc/gen_ndr/nbt.h: gen_ndr/nbt.h librpc/gen_ndr/ntp_signd.h: gen_ndr/ntp_signd.h -librpc/gen_ndr/ndr_ntp_signd.h: gen_ndr/ndr_ntp_signd.h librpc/gen_ndr/svcctl.h: gen_ndr/svcctl.h librpc/gen_ndr/ndr_svcctl.h: gen_ndr/ndr_svcctl.h librpc/gen_ndr/ndr_svcctl_c.h: gen_ndr/ndr_svcctl_c.h diff --git a/source4/librpc/config.mk b/source4/librpc/config.mk index fd628a2788..d2e11959e8 100644 --- a/source4/librpc/config.mk +++ b/source4/librpc/config.mk @@ -343,8 +343,6 @@ PUBLIC_DEPENDENCIES = LIBNDR NDR_NTP_SIGND_OBJ_FILES = $(gen_ndrsrcdir)/ndr_ntp_signd.o -PUBLIC_HEADERS += $(gen_ndrsrcdir)/ndr_ntp_signd.h - [SUBSYSTEM::NDR_WINSREPL] PUBLIC_DEPENDENCIES = LIBNDR NDR_NBT diff --git a/source4/librpc/idl/ntp_signd.idl b/source4/librpc/idl/ntp_signd.idl index 2863401389..2b2fbc7662 100644 --- a/source4/librpc/idl/ntp_signd.idl +++ b/source4/librpc/idl/ntp_signd.idl @@ -12,10 +12,18 @@ interface ntp_signd { + typedef [v1_enum] enum { + SIGN_TO_CLIENT = 0, + ASK_SERVER_TO_SIGN = 1, + CHECK_SERVER_SIGNATURE = 2, + SIGNING_SUCCESS = 3, + SIGNING_FAILURE = 4 + } ntp_signd_op; + typedef [flag(NDR_BIG_ENDIAN),public] struct { uint32 version; - uint32 op; - uint32 packet_id; + ntp_signd_op op; + uint16 packet_id; [flag(NDR_LITTLE_ENDIAN)] uint32 key_id; [flag(NDR_REMAINING)] DATA_BLOB packet_to_sign; @@ -23,7 +31,7 @@ interface ntp_signd typedef [flag(NDR_BIG_ENDIAN),public] struct samba_key_out { uint32 version; - uint32 op; + ntp_signd_op op; uint32 packet_id; [flag(NDR_REMAINING)] DATA_BLOB signed_packet; } signed_reply; diff --git a/source4/ntp_signd/ntp_signd.c b/source4/ntp_signd/ntp_signd.c index 35016d5c61..fdd97e475c 100644 --- a/source4/ntp_signd/ntp_signd.c +++ b/source4/ntp_signd/ntp_signd.c @@ -34,6 +34,8 @@ #include "libcli/security/security.h" #include "lib/ldb/include/ldb.h" #include "lib/ldb/include/ldb_errors.h" +#include "lib/crypto/md5.h" +#include "system/passwd.h" /* top level context structure for the ntp_signd server @@ -61,27 +63,76 @@ static void ntp_signd_terminate_connection(struct ntp_signd_connection *ntp_sign stream_terminate_connection(ntp_signdconn->conn, reason); } +static NTSTATUS signing_failure(struct ntp_signd_connection *ntp_signdconn, + uint32_t packet_id) +{ + NTSTATUS status; + struct signed_reply signed_reply; + TALLOC_CTX *tmp_ctx = talloc_new(ntp_signdconn); + DATA_BLOB reply, blob; + enum ndr_err_code ndr_err; + + NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); + + signed_reply.version = 1; + signed_reply.op = SIGNING_FAILURE; + signed_reply.packet_id = packet_id; + signed_reply.signed_packet = data_blob(NULL, 0); + + ndr_err = ndr_push_struct_blob(&reply, tmp_ctx, + lp_iconv_convenience(ntp_signdconn->ntp_signd->task->lp_ctx), + &signed_reply, + (ndr_push_flags_fn_t)ndr_push_signed_reply); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(1,("failed to push ntp error reply\n")); + talloc_free(tmp_ctx); + return ndr_map_error2ntstatus(ndr_err); + } + + blob = data_blob_talloc(ntp_signdconn, NULL, reply.length + 4); + if (!blob.data) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + RSIVAL(blob.data, 0, reply.length); + memcpy(blob.data + 4, reply.data, reply.length); + + status = packet_send(ntp_signdconn->packet, blob); + + /* the call isn't needed any more */ + talloc_free(tmp_ctx); + + return status; +} + /* receive a full packet on a NTP_SIGND connection */ -static NTSTATUS ntp_signd_recv(void *private, DATA_BLOB blob) +static NTSTATUS ntp_signd_recv(void *private, DATA_BLOB wrapped_input) { struct ntp_signd_connection *ntp_signdconn = talloc_get_type(private, struct ntp_signd_connection); NTSTATUS status = NT_STATUS_UNSUCCESSFUL; TALLOC_CTX *tmp_ctx = talloc_new(ntp_signdconn); - DATA_BLOB input, reply; + DATA_BLOB input, output, wrapped_output; const struct dom_sid *domain_sid; struct dom_sid *sid; struct sign_request sign_request; + struct signed_reply signed_reply; enum ndr_err_code ndr_err; struct ldb_result *res; const char *attrs[] = { "unicodePwd", NULL }; + struct MD5Context ctx; + struct samr_Password *nt_hash; int ret; - talloc_steal(tmp_ctx, blob.data); + NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); + + talloc_steal(tmp_ctx, wrapped_input.data); - input = data_blob_const(blob.data + 4, blob.length - 4); + input = data_blob_const(wrapped_input.data + 4, wrapped_input.length - 4); ndr_err = ndr_pull_struct_blob_all(&input, tmp_ctx, lp_iconv_convenience(ntp_signdconn->ntp_signd->task->lp_ctx), @@ -94,43 +145,98 @@ static NTSTATUS ntp_signd_recv(void *private, DATA_BLOB blob) return ndr_map_error2ntstatus(ndr_err); } + /* We need to implement 'check signature' and 'request server + * to sign' operations at some point */ + if (sign_request.op != SIGN_TO_CLIENT) { + talloc_free(tmp_ctx); + return signing_failure(ntp_signdconn, sign_request.packet_id); + } + domain_sid = samdb_domain_sid(ntp_signdconn->ntp_signd->samdb); if (!domain_sid) { - return NT_STATUS_INVALID_PARAMETER; + talloc_free(tmp_ctx); + return signing_failure(ntp_signdconn, sign_request.packet_id); } + /* The top bit is a 'key selector' */ sid = dom_sid_add_rid(tmp_ctx, domain_sid, sign_request.key_id & 0x7FFFFFFF); if (!sid) { - return NT_STATUS_NO_MEMORY; + talloc_free(tmp_ctx); + return signing_failure(ntp_signdconn, sign_request.packet_id); } - /* Sign packet */ ret = ldb_search_exp_fmt(ntp_signdconn->ntp_signd->samdb, tmp_ctx, &res, samdb_base_dn(ntp_signdconn->ntp_signd->samdb), LDB_SCOPE_SUBTREE, attrs, "(&(objectSid=%s)(objectClass=computer))", dom_sid_string(tmp_ctx, sid)); if (ret != LDB_SUCCESS) { - return NT_STATUS_UNSUCCESSFUL; + DEBUG(2, ("Failed to search for SID %s in SAM for NTP signing: %s\n", dom_sid_string(tmp_ctx, sid), + ldb_errstring(ntp_signdconn->ntp_signd->samdb))); + talloc_free(tmp_ctx); + return signing_failure(ntp_signdconn, sign_request.packet_id); + } + + if (res->count == 0) { + DEBUG(5, ("Failed to find SID %s in SAM for NTP signing\n", dom_sid_string(tmp_ctx, sid))); + } else if (res->count != 1) { + DEBUG(1, ("Found SID %s %u times in SAM for NTP signing\n", dom_sid_string(tmp_ctx, sid), res->count)); + talloc_free(tmp_ctx); + return signing_failure(ntp_signdconn, sign_request.packet_id); + } + + nt_hash = samdb_result_hash(tmp_ctx, res->msgs[0], "unicodePwd"); + if (!nt_hash) { + DEBUG(1, ("No unicodePwd found on record of SID %s for NTP signing\n", dom_sid_string(tmp_ctx, sid))); + talloc_free(tmp_ctx); + return signing_failure(ntp_signdconn, sign_request.packet_id); } - if (res->count != 1) { - return NT_STATUS_NO_SUCH_USER; + /* Generate the reply packet */ + signed_reply.version = 1; + signed_reply.packet_id = sign_request.packet_id; + signed_reply.op = SIGNING_SUCCESS; + signed_reply.signed_packet = data_blob_talloc(tmp_ctx, + NULL, + sign_request.packet_to_sign.length + 20); + + if (!signed_reply.signed_packet.data) { + talloc_free(tmp_ctx); + return signing_failure(ntp_signdconn, sign_request.packet_id); } + memcpy(signed_reply.signed_packet.data, sign_request.packet_to_sign.data, sign_request.packet_to_sign.length); + SIVAL(signed_reply.signed_packet.data, sign_request.packet_to_sign.length, sign_request.key_id); + /* Sign the NTP response with the unicodePwd */ + MD5Init(&ctx); + MD5Update(&ctx, nt_hash->hash, sizeof(nt_hash->hash)); + MD5Update(&ctx, sign_request.packet_to_sign.data, sign_request.packet_to_sign.length); + MD5Final(signed_reply.signed_packet.data + sign_request.packet_to_sign.length + 4, &ctx); + /* Place it into the packet for the wire */ + ndr_err = ndr_push_struct_blob(&output, tmp_ctx, + lp_iconv_convenience(ntp_signdconn->ntp_signd->task->lp_ctx), + &signed_reply, + (ndr_push_flags_fn_t)ndr_push_signed_reply); - blob = data_blob_talloc(ntp_signdconn, NULL, reply.length + 4); - if (!blob.data) { + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(1,("failed to push ntp error reply\n")); + talloc_free(tmp_ctx); + return ndr_map_error2ntstatus(ndr_err); + } + + wrapped_output = data_blob_talloc(ntp_signdconn, NULL, output.length + 4); + if (!wrapped_output.data) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } - RSIVAL(blob.data, 0, reply.length); - memcpy(blob.data + 4, reply.data, reply.length); + /* The 'wire' transport for this is wrapped with a 4 byte network byte order length */ + RSIVAL(wrapped_output.data, 0, output.length); + memcpy(wrapped_output.data + 4, output.data, output.length); - status = packet_send(ntp_signdconn->packet, blob); + status = packet_send(ntp_signdconn->packet, wrapped_output); /* the call isn't needed any more */ talloc_free(tmp_ctx); @@ -215,7 +321,15 @@ static void ntp_signd_task_init(struct task_server *task) const struct model_ops *model_ops; - const char *address = "/tmp/ux_demo"; + const char *address; + + if (!directory_create_or_exist(lp_ntp_signd_socket_directory(task->lp_ctx), geteuid(), 0755)) { + char *error = talloc_asprintf(task, "Cannot create NTP signd pipe directory: %s", + lp_ntp_signd_socket_directory(task->lp_ctx)); + task_server_terminate(task, + error); + return; + } /* within the ntp_signd task we want to be a single process, so ask for the single process model ops and pass these to the @@ -236,12 +350,15 @@ static void ntp_signd_task_init(struct task_server *task) ntp_signd->task = task; - ntp_signd->samdb = samdb_connect(ntp_signd, task->event_ctx, task->lp_ctx, anonymous_session(ntp_signd, task->event_ctx, task->lp_ctx)); + /* Must be system to get at the password hashes */ + ntp_signd->samdb = samdb_connect(ntp_signd, task->event_ctx, task->lp_ctx, system_session(ntp_signd, task->lp_ctx)); if (ntp_signd->samdb == NULL) { task_server_terminate(task, "ntp_signd failed to open samdb"); return; } + address = talloc_asprintf(ntp_signd, "%s/socket", lp_ntp_signd_socket_directory(task->lp_ctx)); + status = stream_setup_socket(ntp_signd->task->event_ctx, ntp_signd->task->lp_ctx, model_ops, diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index ad1752a7e7..0a7aec1985 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -179,6 +179,7 @@ struct loadparm_global int bUnixExtensions; int bDisableNetbios; int bRpcBigEndian; + char *szNTPSignDSocketDirectory; struct param_opt *param_opt; }; @@ -489,6 +490,8 @@ static struct parm_struct parm_table[] = { {"template homedir", P_STRING, P_GLOBAL, GLOBAL_VAR(szTemplateHomedir), NULL, NULL }, {"idmap trusted only", P_BOOL, P_GLOBAL, GLOBAL_VAR(bIdmapTrustedOnly), NULL, NULL}, + {"ntp signd socket directory", P_STRING, P_GLOBAL, GLOBAL_VAR(szNTPSignDSocketDirectory), NULL, NULL }, + {NULL, P_BOOL, P_NONE, 0, NULL, NULL} }; @@ -730,6 +733,8 @@ _PUBLIC_ FN_LOCAL_INTEGER(lp_force_dir_mode, iDir_force_mode) _PUBLIC_ FN_GLOBAL_INTEGER(lp_server_signing, server_signing) _PUBLIC_ FN_GLOBAL_INTEGER(lp_client_signing, client_signing) +_PUBLIC_ FN_GLOBAL_CONST_STRING(lp_ntp_signd_socket_directory, szNTPSignDSocketDirectory) + /* local prototypes */ static int map_parameter(const char *pszParmName); static struct loadparm_service *getservicebyname(struct loadparm_context *lp_ctx, @@ -2410,6 +2415,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lp_do_global_parameter(lp_ctx, "prefork children:smb", "4"); + lp_do_global_parameter(lp_ctx, "ntp signd socket directory", dyn_NTP_SIGND_SOCKET_DIR); + for (i = 0; parm_table[i].label; i++) { if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) { lp_ctx->flags[i] |= FLAG_DEFAULT; diff --git a/source4/param/param.h b/source4/param/param.h index 0b276cdff2..06a42575ad 100644 --- a/source4/param/param.h +++ b/source4/param/param.h @@ -186,6 +186,8 @@ int lp_dir_mask(struct loadparm_service *, struct loadparm_service *); int lp_force_dir_mode(struct loadparm_service *, struct loadparm_service *); int lp_server_signing(struct loadparm_context *); int lp_client_signing(struct loadparm_context *); +const char *lp_ntp_signd_socket_directory(struct loadparm_context *); + const char *lp_get_parametric(struct loadparm_context *lp_ctx, struct loadparm_service *service, const char *type, const char *option); |