summaryrefslogtreecommitdiff
path: root/daemon/ntlmssp.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/ntlmssp.c')
-rw-r--r--daemon/ntlmssp.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/daemon/ntlmssp.c b/daemon/ntlmssp.c
new file mode 100644
index 0000000..3edb63b
--- /dev/null
+++ b/daemon/ntlmssp.c
@@ -0,0 +1,398 @@
+/*
+ * $Id$
+ *
+ */
+
+#include "ntlmssp.h"
+#include "smblib/smblib-priv.h"
+
+#define little_endian_word(x) x[0] + (((unsigned)x[1]) << 8)
+/* fhz 02-02-09: typecasting is needed for a generic use */
+#define set_little_endian_word(x,y) (*((char *)x))=(y&0xff);*(((char*)x)+1)=((y>>8)&0xff)
+
+int ntlm_msg_type(unsigned char *raw_msg, unsigned msglen)
+{
+ struct ntlm_msg1 *msg = (struct ntlm_msg1 *) raw_msg;
+
+ if (msglen < 9)
+ return -1;
+ if (strncmp(msg->protocol, "NTLMSSP", 8))
+ return -1;
+ return msg->type;
+}
+
+static int
+ntlm_extract_mem(unsigned char *dst,
+ unsigned char *src, unsigned srclen,
+ unsigned char *off, unsigned char *len,
+ unsigned max)
+{
+ unsigned o = little_endian_word(off);
+ unsigned l = little_endian_word(len);
+ if (l > max)
+ return -1;
+ if (o >= srclen)
+ return -1;
+ if (o + l > srclen)
+ return -1;
+ src += o;
+ while (l-- > 0)
+ *dst++ = *src++;
+ return 0;
+}
+
+static int
+ntlm_extract_string(unsigned char *dst,
+ unsigned char *src, unsigned srclen,
+ unsigned char *off, unsigned char *len,
+ unsigned max)
+{
+ unsigned o = little_endian_word(off);
+ unsigned l = little_endian_word(len);
+ if (l > max)
+ return -1;
+ if (o >= srclen)
+ return -1;
+ if (o + l > srclen)
+ return -1;
+ src += o;
+ while (l-- > 0) {
+ if(*src != '\0' ) {
+ *dst = *src;
+ dst++;
+ }
+ src++;
+ }
+ *dst = 0;
+ return 0;
+}
+
+static int
+ntlm_put_in_unicode(unsigned char *dst,
+ unsigned char *src, unsigned srclen, unsigned max)
+{
+ unsigned l = srclen*2;
+ if (l > max)
+ l=max; /* fhz: bad very bad */
+ while (l > 0) {
+ /* ASCII to unicode*/
+ *dst++ = *src++;
+ *dst++=0;
+ l -=2;
+ }
+ return 0;
+
+
+
+}
+
+static int
+ntlm_extract_unicode(unsigned char *dst,
+ unsigned char *src, unsigned srclen,
+ unsigned char *off, unsigned char *len,
+ unsigned max)
+{
+ unsigned o = little_endian_word(off);
+ unsigned l = little_endian_word(len) / 2; /* Unicode! */
+ if (l > max)
+ return -1;
+ if (o >= srclen)
+ return -1;
+ if (o + l > srclen)
+ return -1;
+ src += o;
+ while (l > 0) {
+ /* Unicode to ASCII */
+ *dst++ = *src;
+ src += 2;
+ l -= 2;
+ }
+ *dst = 0;
+ return 0;
+}
+
+static int
+ntlm_msg1_getntlmssp_flags(unsigned char *raw_msg,
+ unsigned char *ntlmssp_flags)
+{
+ struct ntlm_msg1 *msg = (struct ntlm_msg1 *) raw_msg;
+ *ntlmssp_flags=little_endian_word(msg->flags);
+ return 0;
+}
+
+static int
+ntlm_msg1_gethostname(unsigned char *raw_msg,
+ unsigned msglen, unsigned char *hostname)
+{
+ struct ntlm_msg1 *msg = (struct ntlm_msg1 *) raw_msg;
+ if (ntlm_extract_string(hostname, (char *) msg, msglen,
+ msg->host_off, msg->host_len, MAX_HOSTLEN))
+ return 1;
+ return 0;
+}
+
+static int
+ntlm_msg1_getdomainname(unsigned char *raw_msg,
+ unsigned msglen, unsigned char *domainname)
+{
+ struct ntlm_msg1 *msg = (struct ntlm_msg1 *) raw_msg;
+ if (ntlm_extract_string(domainname, (char *) msg,
+ msglen, msg->dom_off, msg->dom_len, MAX_DOMLEN))
+ return 2;
+ return 0;
+}
+
+static int
+ntlm_msg3_getlm(unsigned char *raw_msg, unsigned msglen,
+ unsigned char *lm)
+{
+ struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
+ if (ntlm_extract_mem(lm, (char *) msg, msglen, msg->lm_off,
+ msg->lm_len, RESP_LEN))
+ return 4;
+ return 0;
+}
+
+static int
+ntlm_msg3_getnt(unsigned char *raw_msg, unsigned msglen,
+ unsigned char *nt)
+{
+ struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
+ if (ntlm_extract_mem(nt, (char *) msg, msglen, msg->nt_off,
+ msg->nt_len, RESP_LEN))
+ /* Win9x: we can't extract nt ... so we use lm... */
+ if (ntlm_extract_mem(nt, (char *) msg, msglen, msg->lm_off,
+ msg->lm_len, RESP_LEN))
+ return 8;
+ return 0;
+}
+
+static int
+ntlm_msg3_getusername(unsigned char *raw_msg,
+ unsigned msglen, unsigned char *username,
+ unsigned ntlmssp_flags)
+{
+ struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
+ int c;
+ if (ntlmssp_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ if (ntlm_extract_unicode(username, (char *) msg, msglen,
+ msg->user_off, msg->user_len, MAX_USERLEN))
+ return 16;
+ }
+ else { /* ascii */
+ if (ntlm_extract_string(username, (char *) msg, msglen,
+ msg->user_off, msg->user_len, MAX_USERLEN))
+ return 16;
+ else {
+ /* Win9x client leave username in uppercase...fix it: */
+ while (*username!=(unsigned char)NULL) {
+ c=tolower((int)*username);
+ *username=(unsigned char)c;
+ username++;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+ntlm_msg3_gethostname(unsigned char *raw_msg, unsigned msglen,
+ unsigned char *hostname,unsigned ntlmssp_flags)
+{
+ struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
+ if (ntlmssp_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ if (ntlm_extract_unicode(hostname, (char *) msg, msglen,
+ msg->host_off, msg->host_len, MAX_HOSTLEN))
+ return 0; /* this one FAILS, but since the value is not used,
+ * we just pretend it was ok. */
+ }
+ else { /* ascii */
+ if (ntlm_extract_string(hostname, (char *) msg, msglen,
+ msg->host_off, msg->host_len, MAX_HOSTLEN))
+ return 0; /* this one FAILS, but since the value is not used,
+ * we just pretend it was ok. */
+ }
+ return 0;
+}
+
+static int
+ntlm_msg3_getdomainname(unsigned char *raw_msg,
+ unsigned msglen, unsigned char *domainname,
+ unsigned ntlmssp_flags)
+{
+ struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
+ if (ntlmssp_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ if (ntlm_extract_unicode(domainname, (char *) msg, msglen,
+ msg->dom_off, msg->dom_len, MAX_DOMLEN))
+ return 64;
+ }
+ else { /* asii */
+ if (ntlm_extract_string(domainname, (char *) msg, msglen,
+ msg->dom_off, msg->dom_len, MAX_DOMLEN))
+ return 64;
+ }
+ return 0;
+}
+
+int ntlmssp_decode_msg(struct ntlmssp_info *info,
+ unsigned char *raw_msg, unsigned msglen,
+ unsigned *ntlmssp_flags)
+{
+ unsigned char flags;
+ int ret;
+ switch (info->msg_type = ntlm_msg_type(raw_msg, msglen)) {
+ case 1:
+ ret = ntlm_msg1_getntlmssp_flags(raw_msg,&flags);
+ *ntlmssp_flags = (unsigned) flags;
+ return ntlm_msg1_gethostname(raw_msg, msglen, info->host)
+ + ntlm_msg1_getdomainname(raw_msg, msglen, info->domain);
+ case 3:
+ return ntlm_msg3_getlm(raw_msg, msglen, info->lm)
+ + ntlm_msg3_getnt(raw_msg, msglen, info->nt)
+ + ntlm_msg3_getusername(raw_msg, msglen, info->user,*ntlmssp_flags)
+ + ntlm_msg3_gethostname(raw_msg, msglen, info->host,*ntlmssp_flags)
+ + ntlm_msg3_getdomainname(raw_msg, msglen, info->domain,*ntlmssp_flags);
+ }
+ return -1;
+}
+
+int ntlmssp_encode_msg2(unsigned char *nonce, struct ntlm_msg2 *msg)
+{
+ memset(msg, 0, sizeof(struct ntlm_msg2));
+ strcpy(msg->protocol, "NTLMSSP");
+ msg->type = 0x02;
+ set_little_endian_word(msg->msg_len, sizeof(struct ntlm_msg2));
+ set_little_endian_word(msg->flags, 0x8201);
+ memcpy(msg->nonce, nonce, sizeof(msg->nonce));
+ return 0;
+}
+
+int ntlmssp_encode_msg2_win9x(unsigned char *nonce, struct ntlm_msg2_win9x *msg,char *domainname,unsigned ntlmssp_flags)
+{
+ unsigned int size,len,flags;
+
+ memset(msg, 0, sizeof(struct ntlm_msg2_win9x));
+ strcpy(msg->protocol, "NTLMSSP");
+ msg->type = 0x02;
+ if (ntlmssp_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ /* unicode case */
+
+ len=strlen(domainname);
+ ntlm_put_in_unicode((char *)msg->dom,domainname,
+ len, MAX_DOMLEN);
+ len=len*2;
+ if (len>MAX_DOMLEN)
+ len=MAX_DOMLEN; /* fhz: bad very bad */
+ flags=NTLM_NTLMSSP_NEG_FLAGS | NTLMSSP_NEGOTIATE_UNICODE;
+ } else {
+ /* ascii case */
+ len=strlen(domainname);
+ if (len>MAX_DOMLEN)
+ len=MAX_DOMLEN; /* fhz: bad very bad */
+ strncpy(msg->dom,domainname,len);
+ flags=NTLM_NTLMSSP_NEG_FLAGS;
+ }
+ size=NTLM_MSG2_WIN9X_FIXED_SIZE+len;
+ set_little_endian_word(msg->dom_off, NTLM_MSG2_WIN9X_FIXED_SIZE);
+ set_little_endian_word(msg->dom_len1,len);
+ set_little_endian_word(msg->dom_len2,len);
+ set_little_endian_word(msg->msg_len,size);
+ set_little_endian_word(msg->flags,flags);
+ if (ntlmssp_flags & NTLMSSP_REQUEST_TARGET)
+ set_little_endian_word(msg->zero2, 0x01); /* == set NTLMSSP_TARGET_TYPE_DOMAIN */
+
+ memcpy(msg->nonce, nonce, sizeof(msg->nonce));
+ return size;
+}
+
+
+int ntlmssp_validuser(const char* username, const char* password, const char* server,
+ const char* backup, const char* domain)
+{
+ char *SMB_Prots[] =
+ {"PC NETWORK PROGRAM 1.0",
+ "MICROSOFT NETWORKS 1.03",
+ "MICROSOFT NETWORKS 3.0",
+ "LANMAN1.0",
+ "LM1.2X002",
+ "Samba",
+ "NT LM 0.12",
+ "NT LANMAN 1.0",
+ NULL};
+ SMB_Handle_Type con;
+
+ SMB_Init();
+ con = SMB_Connect_Server(NULL, (char*)server);
+ if (con == NULL) { /* Error ... */
+ con = SMB_Connect_Server(NULL, (char*)backup);
+ if (con == NULL) {
+ return (NTV_SERVER_ERROR);
+ }
+ }
+ if (SMB_Negotiate(con, SMB_Prots) < 0) { /* An error */
+ SMB_Discon(con, 0);
+ return (NTV_PROTOCOL_ERROR);
+ }
+ /* Test for a server in share level mode do not authenticate against
+ * it */
+ if (con->Security == 0) {
+ SMB_Discon(con, 0);
+ return (NTV_PROTOCOL_ERROR);
+ }
+ if (SMB_Logon_Server(con, (char*)username, (char*)password, 0, (char*)domain) < 0) {
+ SMB_Discon(con, 0);
+ return (NTV_LOGON_ERROR);
+ }
+ SMB_Discon(con, 0);
+ return (NTV_NO_ERROR);
+}
+
+void* ntlmssp_connect(const char* server, const char* backup, const char* domain, char* nonce)
+{
+ char *SMB_Prots[] =
+ {"PC NETWORK PROGRAM 1.0",
+ "MICROSOFT NETWORKS 1.03",
+ "MICROSOFT NETWORKS 3.0",
+ "LANMAN1.0",
+ "LM1.2X002",
+ "Samba",
+ "NT LM 0.12",
+ "NT LANMAN 1.0",
+ NULL};
+ SMB_Handle_Type con;
+
+ SMB_Init();
+ con = SMB_Connect_Server(NULL, (char*)server);
+ if (con == NULL) { /* Error ... */
+ con = SMB_Connect_Server(NULL, (char*)backup);
+ if (con == NULL) {
+ return (NULL);
+ }
+ }
+ if (SMB_Negotiate(con, SMB_Prots) < 0) { /* An error */
+ SMB_Discon(con, 0);
+ return (NULL);
+ }
+ /* Test for a server in share level mode do not authenticate
+ * against it */
+ if (con->Security == 0) {
+ SMB_Discon(con, 0);
+ return (NULL);
+ }
+ memcpy(nonce, con->Encrypt_Key, 8);
+
+ return con;
+}
+
+int ntlmssp_auth(void* handle, const char* user, const char* password, int flag, char* domain)
+{
+ if (SMB_Logon_Server(handle, (char*)user, (char*)password, flag, (char*)domain) < 0) {
+ return (NTV_LOGON_ERROR);
+ }
+ return NTV_NO_ERROR;
+}
+
+void ntlmssp_disconnect(void* handle)
+{
+ SMB_Discon(handle, 0);
+}