diff options
Diffstat (limited to 'source/libsmb')
-rw-r--r-- | source/libsmb/.cvsignore | 0 | ||||
-rw-r--r-- | source/libsmb/clientgen.c | 1905 | ||||
-rw-r--r-- | source/libsmb/credentials.c | 222 | ||||
-rw-r--r-- | source/libsmb/namequery.c | 575 | ||||
-rw-r--r-- | source/libsmb/nmblib.c | 713 | ||||
-rw-r--r-- | source/libsmb/nterr.c | 543 | ||||
-rw-r--r-- | source/libsmb/pwd_cache.c | 235 | ||||
-rw-r--r-- | source/libsmb/smbdes.c | 399 | ||||
-rw-r--r-- | source/libsmb/smbencrypt.c | 139 | ||||
-rw-r--r-- | source/libsmb/smberr.c | 181 |
10 files changed, 4467 insertions, 445 deletions
diff --git a/source/libsmb/.cvsignore b/source/libsmb/.cvsignore new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/source/libsmb/.cvsignore diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c new file mode 100644 index 00000000000..30f7dc5d99e --- /dev/null +++ b/source/libsmb/clientgen.c @@ -0,0 +1,1905 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + SMB client generic functions + Copyright (C) Andrew Tridgell 1994-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define NO_SYSLOG + +#include "includes.h" +#include "trans2.h" + + +extern int DEBUGLEVEL; + +/***************************************************** + RAP error codes - a small start but will be extended. +*******************************************************/ + +struct +{ + int err; + char *message; +} rap_errmap[] = +{ + {5, "User has insufficient privilege" }, + {86, "The specified password is invalid" }, + {2226, "Operation only permitted on a Primary Domain Controller" }, + {2242, "The password of this user has expired." }, + {2243, "The password of this user cannot change." }, + {2244, "This password cannot be used now (password history conflict)." }, + {2245, "The password is shorter than required." }, + {2246, "The password of this user is too recent to change."}, + {0, NULL} +}; + +/**************************************************************************** + return a description of an SMB error +****************************************************************************/ +static char *cli_smb_errstr(struct cli_state *cli) +{ + return smb_errstr(cli->inbuf); +} + +/****************************************************** + Return an error message - either an SMB error or a RAP + error. +*******************************************************/ + +char *cli_errstr(struct cli_state *cli) +{ + static fstring error_message; + int errclass; + int errnum; + int i; + + /* + * Errors are of three kinds - smb errors, + * dealt with by cli_smb_errstr, NT errors, + * whose code is in cli.nt_error, and rap + * errors, whose error code is in cli.rap_error. + */ + + cli_error(cli, &errclass, &errnum); + if(errclass != 0) + return cli_smb_errstr(cli); + + /* + * Was it an NT error ? + */ + + if(cli->nt_error) { + char *nt_msg = get_nt_error_msg(cli->nt_error); + + if(nt_msg == NULL) + slprintf(error_message, sizeof(fstring) - 1, "NT code %d", cli->nt_error); + else + fstrcpy(error_message, nt_msg); + + return error_message; + } + + /* + * Must have been a rap error. + */ + + slprintf(error_message, sizeof(error_message) - 1, "code %d", cli->rap_error); + + for(i = 0; rap_errmap[i].message != NULL; i++) { + if (rap_errmap[i].err == cli->rap_error) { + fstrcpy( error_message, rap_errmap[i].message); + break; + } + } + + return error_message; +} + +/**************************************************************************** +setup basics in a outgoing packet +****************************************************************************/ +static void cli_setup_packet(struct cli_state *cli) +{ + cli->rap_error = 0; + cli->nt_error = 0; + SSVAL(cli->outbuf,smb_pid,cli->pid); + SSVAL(cli->outbuf,smb_uid,cli->uid); + SSVAL(cli->outbuf,smb_mid,cli->mid); + if (cli->protocol > PROTOCOL_CORE) { + SCVAL(cli->outbuf,smb_flg,0x8); + SSVAL(cli->outbuf,smb_flg2,0x1); + } +} + + +/**************************************************************************** + send a SMB trans or trans2 request + ****************************************************************************/ +static BOOL cli_send_trans(struct cli_state *cli, int trans, + char *name, int pipe_name_len, + int fid, int flags, + uint16 *setup, int lsetup, int msetup, + char *param, int lparam, int mparam, + char *data, int ldata, int mdata) +{ + int i; + int this_ldata,this_lparam; + int tot_data=0,tot_param=0; + char *outdata,*outparam; + char *p; + + this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */ + this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam)); + + bzero(cli->outbuf,smb_size); + set_message(cli->outbuf,14+lsetup,0,True); + CVAL(cli->outbuf,smb_com) = trans; + SSVAL(cli->outbuf,smb_tid, cli->cnum); + cli_setup_packet(cli); + + outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 3); + outdata = outparam+this_lparam; + + /* primary request */ + SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */ + SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */ + SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */ + SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */ + SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */ + SSVAL(cli->outbuf,smb_flags,flags); /* flags */ + SIVAL(cli->outbuf,smb_timeout,0); /* timeout */ + SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */ + SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */ + SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */ + SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */ + SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */ + for (i=0;i<lsetup;i++) /* setup[] */ + SSVAL(cli->outbuf,smb_setup+i*2,setup[i]); + p = smb_buf(cli->outbuf); + if (trans==SMBtrans) { + memcpy(p,name, pipe_name_len + 1); /* name[] */ + } else { + *p++ = 0; /* put in a null smb_name */ + *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */ + } + if (this_lparam) /* param[] */ + memcpy(outparam,param,this_lparam); + if (this_ldata) /* data[] */ + memcpy(outdata,data,this_ldata); + set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */ + PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False); + + show_msg(cli->outbuf); + send_smb(cli->fd,cli->outbuf); + + if (this_ldata < ldata || this_lparam < lparam) { + /* receive interim response */ + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout) || + CVAL(cli->inbuf,smb_rcls) != 0) { + return(False); + } + + tot_data = this_ldata; + tot_param = this_lparam; + + while (tot_data < ldata || tot_param < lparam) { + this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */ + this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam)); + + set_message(cli->outbuf,trans==SMBtrans?8:9,0,True); + CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2; + + outparam = smb_buf(cli->outbuf); + outdata = outparam+this_lparam; + + /* secondary request */ + SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */ + SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */ + SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */ + SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */ + SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */ + SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */ + SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */ + SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */ + if (trans==SMBtrans2) + SSVALS(cli->outbuf,smb_sfid,fid); /* fid */ + if (this_lparam) /* param[] */ + memcpy(outparam,param,this_lparam); + if (this_ldata) /* data[] */ + memcpy(outdata,data,this_ldata); + set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */ + PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False); + + show_msg(cli->outbuf); + send_smb(cli->fd,cli->outbuf); + + tot_data += this_ldata; + tot_param += this_lparam; + } + } + + return(True); +} + + +/**************************************************************************** + receive a SMB trans or trans2 response allocating the necessary memory + ****************************************************************************/ +static BOOL cli_receive_trans(struct cli_state *cli,int trans, + char **param, int *param_len, + char **data, int *data_len) +{ + int total_data=0; + int total_param=0; + int this_data,this_param; + + *data_len = *param_len = 0; + + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) + return False; + + show_msg(cli->inbuf); + + /* sanity check */ + if (CVAL(cli->inbuf,smb_com) != trans) { + DEBUG(0,("Expected %s response, got command 0x%02x\n", + trans==SMBtrans?"SMBtrans":"SMBtrans2", + CVAL(cli->inbuf,smb_com))); + return(False); + } + if (CVAL(cli->inbuf,smb_rcls) != 0) + return(False); + + /* parse out the lengths */ + total_data = SVAL(cli->inbuf,smb_tdrcnt); + total_param = SVAL(cli->inbuf,smb_tprcnt); + + /* allocate it */ + *data = Realloc(*data,total_data); + *param = Realloc(*param,total_param); + + while (1) { + this_data = SVAL(cli->inbuf,smb_drcnt); + this_param = SVAL(cli->inbuf,smb_prcnt); + + if (this_data + *data_len > total_data || + this_param + *param_len > total_param) { + DEBUG(1,("Data overflow in cli_receive_trans\n")); + return False; + } + + if (this_data) + memcpy(*data + SVAL(cli->inbuf,smb_drdisp), + smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff), + this_data); + if (this_param) + memcpy(*param + SVAL(cli->inbuf,smb_prdisp), + smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff), + this_param); + *data_len += this_data; + *param_len += this_param; + + /* parse out the total lengths again - they can shrink! */ + total_data = SVAL(cli->inbuf,smb_tdrcnt); + total_param = SVAL(cli->inbuf,smb_tprcnt); + + if (total_data <= *data_len && total_param <= *param_len) + break; + + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) + return False; + + show_msg(cli->inbuf); + + /* sanity check */ + if (CVAL(cli->inbuf,smb_com) != trans) { + DEBUG(0,("Expected %s response, got command 0x%02x\n", + trans==SMBtrans?"SMBtrans":"SMBtrans2", + CVAL(cli->inbuf,smb_com))); + return(False); + } + if (CVAL(cli->inbuf,smb_rcls) != 0) + return(False); + } + + return(True); +} + +/**************************************************************************** +Call a remote api on an arbitrary pipe. takes param, data and setup buffers. +****************************************************************************/ +BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, int pipe_name_len, + uint16 *setup, uint32 setup_count, uint32 max_setup_count, + char *params, uint32 param_count, uint32 max_param_count, + char *data, uint32 data_count, uint32 max_data_count, + char **rparam, uint32 *rparam_count, + char **rdata, uint32 *rdata_count) +{ + if(pipe_name_len == 0) + pipe_name_len = strlen(pipe_name); + + cli_send_trans(cli, SMBtrans, + pipe_name, pipe_name_len, + 0,0, /* fid, flags */ + setup, setup_count, max_setup_count, + params, param_count, max_param_count, + data, data_count, max_data_count); + + return (cli_receive_trans(cli, SMBtrans, + rparam, (int *)rparam_count, + rdata, (int *)rdata_count)); +} + +/**************************************************************************** +call a remote api +****************************************************************************/ +BOOL cli_api(struct cli_state *cli, + char *param, int prcnt, int mprcnt, + char *data, int drcnt, int mdrcnt, + char **rparam, int *rprcnt, + char **rdata, int *rdrcnt) +{ + cli_send_trans(cli,SMBtrans, + PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */ + 0,0, /* fid, flags */ + NULL,0,0, /* Setup, length, max */ + param, prcnt, mprcnt, /* Params, length, max */ + data, drcnt, mdrcnt /* Data, length, max */ + ); + + return (cli_receive_trans(cli,SMBtrans, + rparam, rprcnt, + rdata, rdrcnt)); +} + + +/**************************************************************************** +perform a NetWkstaUserLogon +****************************************************************************/ +BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation) +{ + char *rparam = NULL; + char *rdata = NULL; + char *p; + int rdrcnt,rprcnt; + pstring param; + + memset(param, 0, sizeof(param)); + + /* send a SMBtrans command with api NetWkstaUserLogon */ + p = param; + SSVAL(p,0,132); /* api number */ + p += 2; + pstrcpy(p,"OOWb54WrLh"); + p = skip_string(p,1); + pstrcpy(p,"WB21BWDWWDDDDDDDzzzD"); + p = skip_string(p,1); + SSVAL(p,0,1); + p += 2; + pstrcpy(p,user); + strupper(p); + p += 21; p++; p += 15; p++; + pstrcpy(p, workstation); + strupper(p); + p += 16; + SSVAL(p, 0, BUFFER_SIZE); + p += 2; + SSVAL(p, 0, BUFFER_SIZE); + p += 2; + + if (cli_api(cli, + param, PTR_DIFF(p,param),1024, /* param, length, max */ + NULL, 0, BUFFER_SIZE, /* data, length, max */ + &rparam, &rprcnt, /* return params, return size */ + &rdata, &rdrcnt /* return data, return size */ + )) { + cli->rap_error = SVAL(rparam,0); + p = rdata; + + if (cli->rap_error == 0) { + DEBUG(4,("NetWkstaUserLogon success\n")); + cli->privilages = SVAL(p, 24); + fstrcpy(cli->eff_name,p+2); + } else { + DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error)); + } + } + + if (rparam) free(rparam); + if (rdata) free(rdata); + return (cli->rap_error == 0); +} + +#if UNUSED_CODE +/**************************************************************************** +call a NetShareEnum - try and browse available connections on a host +****************************************************************************/ +BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(char *, uint32, char *)) +{ + char *rparam = NULL; + char *rdata = NULL; + char *p; + int rdrcnt,rprcnt; + pstring param; + int count = -1; + + /* now send a SMBtrans command with api RNetShareEnum */ + p = param; + SSVAL(p,0,0); /* api number */ + p += 2; + pstrcpy(p,"WrLeh"); + p = skip_string(p,1); + pstrcpy(p,"B13BWz"); + p = skip_string(p,1); + SSVAL(p,0,1); + SSVAL(p,2,BUFFER_SIZE); + p += 4; + + if (cli_api(cli, + param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */ + NULL, 0, BUFFER_SIZE, /* data, length, maxlen */ + &rparam, &rprcnt, /* return params, length */ + &rdata, &rdrcnt)) /* return data, length */ + { + int res = SVAL(rparam,0); + int converter=SVAL(rparam,2); + int i; + + if (res == 0) + { + count=SVAL(rparam,4); + p = rdata; + + for (i=0;i<count;i++,p+=20) + { + char *sname = p; + int type = SVAL(p,14); + int comment_offset = IVAL(p,16) & 0xFFFF; + char *cmnt = comment_offset?(rdata+comment_offset-converter):""; + fn(sname, type, cmnt); + } + } + } + + if (rparam) free(rparam); + if (rdata) free(rdata); + + return(count>0); +} +#endif + +/**************************************************************************** +call a NetServerEnum for the specified workgroup and servertype mask. +This function then calls the specified callback function for each name returned. + +The callback function takes 3 arguments: the machine name, the server type and +the comment. +****************************************************************************/ +BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, + void (*fn)(char *, uint32, char *)) +{ + char *rparam = NULL; + char *rdata = NULL; + int rdrcnt,rprcnt; + char *p; + pstring param; + int uLevel = 1; + int count = -1; + + /* send a SMBtrans command with api NetServerEnum */ + p = param; + SSVAL(p,0,0x68); /* api number */ + p += 2; + pstrcpy(p,"WrLehDz"); + p = skip_string(p,1); + + pstrcpy(p,"B16BBDz"); + + p = skip_string(p,1); + SSVAL(p,0,uLevel); + SSVAL(p,2,BUFFER_SIZE); + p += 4; + SIVAL(p,0,stype); + p += 4; + + pstrcpy(p, workgroup); + p = skip_string(p,1); + + if (cli_api(cli, + param, PTR_DIFF(p,param), 8, /* params, length, max */ + NULL, 0, BUFFER_SIZE, /* data, length, max */ + &rparam, &rprcnt, /* return params, return size */ + &rdata, &rdrcnt /* return data, return size */ + )) { + int res = SVAL(rparam,0); + int converter=SVAL(rparam,2); + int i; + + if (res == 0) { + count=SVAL(rparam,4); + p = rdata; + + for (i = 0;i < count;i++, p += 26) { + char *sname = p; + int comment_offset = (IVAL(p,22) & 0xFFFF)-converter; + char *cmnt = comment_offset?(rdata+comment_offset):""; + if (comment_offset < 0 || comment_offset > rdrcnt) continue; + + stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY; + + fn(sname, stype, cmnt); + } + } + } + + if (rparam) free(rparam); + if (rdata) free(rdata); + + return(count > 0); +} + + + + +static struct { + int prot; + char *name; + } +prots[] = + { + {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"}, + {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"}, + {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"}, + {PROTOCOL_LANMAN1,"LANMAN1.0"}, + {PROTOCOL_LANMAN2,"LM1.2X002"}, + {PROTOCOL_LANMAN2,"Samba"}, + {PROTOCOL_NT1,"NT LM 0.12"}, + {PROTOCOL_NT1,"NT LANMAN 1.0"}, + {-1,NULL} + }; + + +/**************************************************************************** +send a session setup +****************************************************************************/ +BOOL cli_session_setup(struct cli_state *cli, + char *user, + char *pass, int passlen, + char *ntpass, int ntpasslen, + char *workgroup) +{ + char *p; + fstring pword; + + if (cli->protocol < PROTOCOL_LANMAN1) + return True; + + if (passlen > sizeof(pword)-1) { + return False; + } + + if(((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) { + /* Null session connect. */ + pword[0] = '\0'; + } else { + if ((cli->sec_mode & 2) && passlen != 24) { + passlen = 24; + SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword); + } else { + memcpy(pword, pass, passlen); + } + } + + /* if in share level security then don't send a password now */ + if (!(cli->sec_mode & 1)) {fstrcpy(pword, "");passlen=1;} + + /* send a session setup command */ + bzero(cli->outbuf,smb_size); + + if (cli->protocol < PROTOCOL_NT1) { + set_message(cli->outbuf,10,1 + strlen(user) + passlen,True); + CVAL(cli->outbuf,smb_com) = SMBsesssetupX; + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit); + SSVAL(cli->outbuf,smb_vwv3,2); + SSVAL(cli->outbuf,smb_vwv4,1); + SIVAL(cli->outbuf,smb_vwv5,cli->sesskey); + SSVAL(cli->outbuf,smb_vwv7,passlen); + p = smb_buf(cli->outbuf); + memcpy(p,pword,passlen); + p += passlen; + pstrcpy(p,user); + strupper(p); + } else { + set_message(cli->outbuf,13,0,True); + CVAL(cli->outbuf,smb_com) = SMBsesssetupX; + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,BUFFER_SIZE); + SSVAL(cli->outbuf,smb_vwv3,2); + SSVAL(cli->outbuf,smb_vwv4,cli->pid); + SIVAL(cli->outbuf,smb_vwv5,cli->sesskey); + SSVAL(cli->outbuf,smb_vwv7,passlen); + SSVAL(cli->outbuf,smb_vwv8,ntpasslen); + p = smb_buf(cli->outbuf); + memcpy(p,pword,passlen); + p += SVAL(cli->outbuf,smb_vwv7); + memcpy(p,ntpass,ntpasslen); + p += SVAL(cli->outbuf,smb_vwv8); + pstrcpy(p,user); + strupper(p); + p = skip_string(p,1); + pstrcpy(p,workgroup); + strupper(p); + p = skip_string(p,1); + pstrcpy(p,"Unix");p = skip_string(p,1); + pstrcpy(p,"Samba");p = skip_string(p,1); + set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False); + } + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) + return False; + + show_msg(cli->inbuf); + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + /* use the returned uid from now on */ + cli->uid = SVAL(cli->inbuf,smb_uid); + + return True; +} + +/**************************************************************************** + Send a uloggoff. +*****************************************************************************/ + +BOOL cli_ulogoff(struct cli_state *cli) +{ + bzero(cli->outbuf,smb_size); + set_message(cli->outbuf,2,0,True); + CVAL(cli->outbuf,smb_com) = SMBulogoffX; + cli_setup_packet(cli); + SSVAL(cli->outbuf,smb_vwv0,0xFF); + SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */ + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) + return False; + + return CVAL(cli->inbuf,smb_rcls) == 0; +} + +/**************************************************************************** +send a tconX +****************************************************************************/ +BOOL cli_send_tconX(struct cli_state *cli, + char *share, char *dev, char *pass, int passlen) +{ + fstring fullshare, pword; + char *p; + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + if (cli->sec_mode & 1) { + passlen = 1; + pass = ""; + } + + if ((cli->sec_mode & 2) && *pass && passlen != 24) { + passlen = 24; + SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword); + } else { + memcpy(pword, pass, passlen); + } + + slprintf(fullshare, sizeof(fullshare)-1, + "\\\\%s\\%s", cli->desthost, share); + + set_message(cli->outbuf,4, + 2 + strlen(fullshare) + passlen + strlen(dev),True); + CVAL(cli->outbuf,smb_com) = SMBtconX; + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,0xFF); + SSVAL(cli->outbuf,smb_vwv3,passlen); + + p = smb_buf(cli->outbuf); + memcpy(p,pword,passlen); + p += passlen; + fstrcpy(p,fullshare); + p = skip_string(p,1); + pstrcpy(p,dev); + + SCVAL(cli->inbuf,smb_rcls, 1); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) + return False; + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + cli->cnum = SVAL(cli->inbuf,smb_tid); + return True; +} + + +/**************************************************************************** +send a tree disconnect +****************************************************************************/ +BOOL cli_tdis(struct cli_state *cli) +{ + bzero(cli->outbuf,smb_size); + set_message(cli->outbuf,0,0,True); + CVAL(cli->outbuf,smb_com) = SMBtdis; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) + return False; + + return CVAL(cli->inbuf,smb_rcls) == 0; +} + +#if UNUSED_CODE +/**************************************************************************** +rename a file +****************************************************************************/ +BOOL cli_mv(struct cli_state *cli, char *fname_src, char *fname_dst) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True); + + CVAL(cli->outbuf,smb_com) = SMBmv; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN); + + p = smb_buf(cli->outbuf); + *p++ = 4; + pstrcpy(p,fname_src); + p = skip_string(p,1); + *p++ = 4; + pstrcpy(p,fname_dst); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} +#endif + +/**************************************************************************** +delete a file +****************************************************************************/ +BOOL cli_unlink(struct cli_state *cli, char *fname) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,1, 2 + strlen(fname),True); + + CVAL(cli->outbuf,smb_com) = SMBunlink; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN); + + p = smb_buf(cli->outbuf); + *p++ = 4; + pstrcpy(p,fname); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} + + +/**************************************************************************** +create a directory +****************************************************************************/ +BOOL cli_mkdir(struct cli_state *cli, char *dname) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,0, 2 + strlen(dname),True); + + CVAL(cli->outbuf,smb_com) = SMBmkdir; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + p = smb_buf(cli->outbuf); + *p++ = 4; + pstrcpy(p,dname); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} + +/**************************************************************************** +remove a directory +****************************************************************************/ +BOOL cli_rmdir(struct cli_state *cli, char *dname) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,0, 2 + strlen(dname),True); + + CVAL(cli->outbuf,smb_com) = SMBrmdir; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + p = smb_buf(cli->outbuf); + *p++ = 4; + pstrcpy(p,dname); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} + + + +/**************************************************************************** +open a file +****************************************************************************/ +int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode) +{ + char *p; + unsigned openfn=0; + unsigned accessmode=0; + + if (flags & O_CREAT) + openfn |= (1<<4); + if (!(flags & O_EXCL)) { + if (flags & O_TRUNC) + openfn |= (1<<1); + else + openfn |= (1<<0); + } + + accessmode = (share_mode<<4); + + if ((flags & O_RDWR) == O_RDWR) { + accessmode |= 2; + } else if ((flags & O_WRONLY) == O_WRONLY) { + accessmode |= 1; + } + +#if defined(O_SYNC) + if ((flags & O_SYNC) == O_SYNC) { + accessmode |= (1<<14); + } +#endif /* O_SYNC */ + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,15,1 + strlen(fname),True); + + CVAL(cli->outbuf,smb_com) = SMBopenX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,0xFF); + SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */ + SSVAL(cli->outbuf,smb_vwv3,accessmode); + SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN); + SSVAL(cli->outbuf,smb_vwv5,0); + SSVAL(cli->outbuf,smb_vwv8,openfn); + + p = smb_buf(cli->outbuf); + pstrcpy(p,fname); + p = skip_string(p,1); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return -1; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return -1; + } + + return SVAL(cli->inbuf,smb_vwv2); +} + + + + +/**************************************************************************** + close a file +****************************************************************************/ +BOOL cli_close(struct cli_state *cli, int fnum) +{ + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,3,0,True); + + CVAL(cli->outbuf,smb_com) = SMBclose; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,fnum); + SIVALS(cli->outbuf,smb_vwv1,-1); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} + + +/**************************************************************************** + lock a file +****************************************************************************/ +BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,8,10,True); + + CVAL(cli->outbuf,smb_com) = SMBlockingX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,fnum); + CVAL(cli->outbuf,smb_vwv3) = 0; + SIVALS(cli->outbuf, smb_vwv4, timeout); + SSVAL(cli->outbuf,smb_vwv6,0); + SSVAL(cli->outbuf,smb_vwv7,1); + + p = smb_buf(cli->outbuf); + SSVAL(p, 0, cli->pid); + SIVAL(p, 2, offset); + SIVAL(p, 6, len); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} + +/**************************************************************************** + unlock a file +****************************************************************************/ +BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,8,10,True); + + CVAL(cli->outbuf,smb_com) = SMBlockingX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,fnum); + CVAL(cli->outbuf,smb_vwv3) = 0; + SIVALS(cli->outbuf, smb_vwv4, timeout); + SSVAL(cli->outbuf,smb_vwv6,1); + SSVAL(cli->outbuf,smb_vwv7,0); + + p = smb_buf(cli->outbuf); + SSVAL(p, 0, cli->pid); + SIVAL(p, 2, offset); + SIVAL(p, 6, len); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} + + +/**************************************************************************** + read from a file +****************************************************************************/ +int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,10,0,True); + + CVAL(cli->outbuf,smb_com) = SMBreadX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,fnum); + SIVAL(cli->outbuf,smb_vwv3,offset); + SSVAL(cli->outbuf,smb_vwv5,size); + SSVAL(cli->outbuf,smb_vwv6,size); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return -1; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return -1; + } + + size = SVAL(cli->inbuf, smb_vwv5); + p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6); + + memcpy(buf, p, size); + + return size; +} + + +/**************************************************************************** + write to a file +****************************************************************************/ +int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,12,size,True); + + CVAL(cli->outbuf,smb_com) = SMBwriteX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,fnum); + SIVAL(cli->outbuf,smb_vwv3,offset); + + SSVAL(cli->outbuf,smb_vwv10,size); + SSVAL(cli->outbuf,smb_vwv11,smb_buf(cli->outbuf) - smb_base(cli->outbuf)); + + p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11); + memcpy(p, buf, size); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return -1; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return -1; + } + + return SVAL(cli->inbuf, smb_vwv2); +} + + +/**************************************************************************** +do a SMBgetatr call +****************************************************************************/ +BOOL cli_getatr(struct cli_state *cli, char *fname, + int *attr, uint32 *size, time_t *t) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,0,strlen(fname)+2,True); + + CVAL(cli->outbuf,smb_com) = SMBgetatr; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + p = smb_buf(cli->outbuf); + *p = 4; + pstrcpy(p+1, fname); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + if (size) { + *size = IVAL(cli->inbuf, smb_vwv3); + } + + if (t) { + *t = make_unix_date3(cli->inbuf+smb_vwv1); + } + + if (attr) { + *attr = SVAL(cli->inbuf,smb_vwv0); + } + + + return True; +} + + +/**************************************************************************** +do a SMBsetatr call +****************************************************************************/ +BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,8,strlen(fname)+4,True); + + CVAL(cli->outbuf,smb_com) = SMBsetatr; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0, attr); + put_dos_date3(cli->outbuf,smb_vwv1, t); + + p = smb_buf(cli->outbuf); + *p = 4; + pstrcpy(p+1, fname); + p = skip_string(p,1); + *p = 4; + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} + +/**************************************************************************** +send a qpathinfo call +****************************************************************************/ +BOOL cli_qpathinfo(struct cli_state *cli, char *fname, + time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size) +{ + int data_len = 0; + int param_len = 0; + uint16 setup = TRANSACT2_QPATHINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + + param_len = strlen(fname) + 7; + + memset(param, 0, param_len); + SSVAL(param, 0, SMB_INFO_STANDARD); + pstrcpy(¶m[6], fname); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, 0, /* Name, length */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 10, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + if (!rdata || data_len < 22) { + return False; + } + + if (c_time) { + *c_time = make_unix_date2(rdata+0); + } + if (a_time) { + *a_time = make_unix_date2(rdata+4); + } + if (m_time) { + *m_time = make_unix_date2(rdata+8); + } + if (size) { + *size = IVAL(rdata, 12); + } + + if (rdata) free(rdata); + if (rparam) free(rparam); + return True; +} + +/**************************************************************************** +send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level +****************************************************************************/ +BOOL cli_qpathinfo2(struct cli_state *cli, char *fname, + time_t *c_time, time_t *a_time, time_t *m_time, + time_t *w_time, uint32 *size) +{ + int data_len = 0; + int param_len = 0; + uint16 setup = TRANSACT2_QPATHINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + + param_len = strlen(fname) + 7; + + memset(param, 0, param_len); + SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO); + pstrcpy(¶m[6], fname); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, 0, /* name, length */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 10, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + if (!rdata || data_len < 22) { + return False; + } + + if (c_time) { + *c_time = interpret_long_date(rdata+0) - cli->serverzone; + } + if (a_time) { + *a_time = interpret_long_date(rdata+8) - cli->serverzone; + } + if (m_time) { + *m_time = interpret_long_date(rdata+16) - cli->serverzone; + } + if (w_time) { + *w_time = interpret_long_date(rdata+24) - cli->serverzone; + } + if (size) { + *size = IVAL(rdata, 40); + } + + if (rdata) free(rdata); + if (rparam) free(rparam); + return True; +} + + +/**************************************************************************** +send a qfileinfo call +****************************************************************************/ +BOOL cli_qfileinfo(struct cli_state *cli, int fnum, + time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size) +{ + int data_len = 0; + int param_len = 0; + uint16 setup = TRANSACT2_QFILEINFO; + pstring param; + char *rparam=NULL, *rdata=NULL; + + param_len = 4; + + memset(param, 0, param_len); + SSVAL(param, 0, fnum); + SSVAL(param, 2, SMB_INFO_STANDARD); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, 0, /* name, length */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + if (!rdata || data_len < 22) { + return False; + } + + if (c_time) { + *c_time = make_unix_date2(rdata+0); + } + if (a_time) { + *a_time = make_unix_date2(rdata+4); + } + if (m_time) { + *m_time = make_unix_date2(rdata+8); + } + if (size) { + *size = IVAL(rdata, 12); + } + + if (rdata) free(rdata); + if (rparam) free(rparam); + return True; +} + +/**************************************************************************** +Send a SamOEMChangePassword command +****************************************************************************/ + +BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password, + char *old_password) +{ + char param[16+sizeof(fstring)]; + char data[532]; + char *p = param; + fstring upper_case_old_pw; + fstring upper_case_new_pw; + unsigned char old_pw_hash[16]; + unsigned char new_pw_hash[16]; + int data_len; + int param_len = 0; + int new_pw_len = strlen(new_password); + char *rparam = NULL; + char *rdata = NULL; + int rprcnt, rdrcnt; + + if(strlen(user) >= sizeof(fstring)-1) { + DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user)); + return False; + } + + if(new_pw_len > 512) { + DEBUG(0,("cli_oem_change_password: new password for user %s is too long.\n", user)); + return False; + } + + SSVAL(p,0,214); /* SamOEMChangePassword command. */ + p += 2; + pstrcpy(p, "zsT"); + p = skip_string(p,1); + pstrcpy(p, "B516B16"); + p = skip_string(p,1); + pstrcpy(p,user); + p = skip_string(p,1); + SSVAL(p,0,532); + p += 2; + + param_len = PTR_DIFF(p,param); + + /* + * Now setup the data area. + * We need to generate a random fill + * for this area to make it harder to + * decrypt. JRA. + */ + generate_random_buffer((unsigned char *)data, sizeof(data), False); + fstrcpy( &data[512 - new_pw_len], new_password); + SIVAL(data, 512, new_pw_len); + + /* + * Get the Lanman hash of the old password, we + * use this as the key to SamOEMHash(). + */ + memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw)); + fstrcpy(upper_case_old_pw, old_password); + strupper(upper_case_old_pw); + E_P16((uchar *)upper_case_old_pw, old_pw_hash); + + SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True); + + /* + * Now place the old password hash in the data. + */ + memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw)); + fstrcpy(upper_case_new_pw, new_password); + strupper(upper_case_new_pw); + + E_P16((uchar *)upper_case_new_pw, new_pw_hash); + + E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]); + + data_len = 532; + + if(cli_send_trans(cli,SMBtrans, + PIPE_LANMAN,strlen(PIPE_LANMAN), /* name, length */ + 0,0, /* fid, flags */ + NULL,0,0, /* setup, length, max */ + param,param_len,2, /* param, length, max */ + data,data_len,0 /* data, length, max */ + ) == False) { + DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n", + user )); + return False; + } + + if(cli_receive_trans(cli,SMBtrans, + &rparam, &rprcnt, + &rdata, &rdrcnt)) { + if(rparam) + cli->rap_error = SVAL(rparam,0); + } + + if (rparam) + free(rparam); + if (rdata) + free(rdata); + + return (cli->rap_error == 0); +} + +/**************************************************************************** +send a negprot command +****************************************************************************/ +BOOL cli_negprot(struct cli_state *cli) +{ + char *p; + int numprots; + int plength; + + bzero(cli->outbuf,smb_size); + + /* setup the protocol strings */ + for (plength=0,numprots=0; + prots[numprots].name && prots[numprots].prot<=cli->protocol; + numprots++) + plength += strlen(prots[numprots].name)+2; + + set_message(cli->outbuf,0,plength,True); + + p = smb_buf(cli->outbuf); + for (numprots=0; + prots[numprots].name && prots[numprots].prot<=cli->protocol; + numprots++) { + *p++ = 2; + pstrcpy(p,prots[numprots].name); + p += strlen(p) + 1; + } + + CVAL(cli->outbuf,smb_com) = SMBnegprot; + cli_setup_packet(cli); + + CVAL(smb_buf(cli->outbuf),0) = 2; + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) + return False; + + show_msg(cli->inbuf); + + if (CVAL(cli->inbuf,smb_rcls) != 0 || + ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) { + return(False); + } + + cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot; + + + if (cli->protocol >= PROTOCOL_NT1) { + /* NT protocol */ + cli->sec_mode = CVAL(cli->inbuf,smb_vwv1); + cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1); + cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1); + cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60; + /* this time arrives in real GMT */ + cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1); + memcpy(cli->cryptkey,smb_buf(cli->inbuf),8); + if (IVAL(cli->inbuf,smb_vwv9+1) & 1) + cli->readbraw_supported = + cli->writebraw_supported = True; + } else if (cli->protocol >= PROTOCOL_LANMAN1) { + cli->sec_mode = SVAL(cli->inbuf,smb_vwv1); + cli->max_xmit = SVAL(cli->inbuf,smb_vwv2); + cli->sesskey = IVAL(cli->inbuf,smb_vwv6); + cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60; + /* this time is converted to GMT by make_unix_date */ + cli->servertime = make_unix_date(cli->inbuf+smb_vwv8); + cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0); + cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0); + memcpy(cli->cryptkey,smb_buf(cli->inbuf),8); + } else { + /* the old core protocol */ + cli->sec_mode = 0; + cli->serverzone = TimeDiff(time(NULL)); + } + + return True; +} + + +/**************************************************************************** + send a session request. see rfc1002.txt 4.3 and 4.3.2 +****************************************************************************/ +BOOL cli_session_request(struct cli_state *cli, + struct nmb_name *calling, struct nmb_name *called) +{ + char *p; + int len = 4; + /* send a session request (RFC 1002) */ + + memcpy(&(cli->calling), calling, sizeof(*calling)); + memcpy(&(cli->called ), called , sizeof(*called )); + + /* put in the destination name */ + p = cli->outbuf+len; + name_mangle(cli->called .name, p, cli->called .name_type); + len += name_len(p); + + /* and my name */ + p = cli->outbuf+len; + name_mangle(cli->calling.name, p, cli->calling.name_type); + len += name_len(p); + + /* setup the packet length */ + _smb_setlen(cli->outbuf,len); + CVAL(cli->outbuf,0) = 0x81; + +#ifdef WITH_SSL +retry: +#endif /* WITH_SSL */ + + send_smb(cli->fd,cli->outbuf); + DEBUG(5,("Sent session request\n")); + + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) + return False; + +#ifdef WITH_SSL + if(CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */ + if(!sslutil_fd_is_ssl(cli->fd)){ + if(sslutil_connect(cli->fd) == 0) + goto retry; + } + } +#endif /* WITH_SSL */ + + if (CVAL(cli->inbuf,0) != 0x82) { + /* This is the wrong place to put the error... JRA. */ + cli->rap_error = CVAL(cli->inbuf,0); + return False; + } + return(True); +} + + +/**************************************************************************** +open the client sockets +****************************************************************************/ +BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip) +{ + struct in_addr dest_ip; + extern struct in_addr ipzero; + + fstrcpy(cli->desthost, host); + + if (!ip || ip_equal(*ip, ipzero)) { + if(!resolve_name( cli->desthost, &dest_ip)) { + return False; + } + } else { + dest_ip = *ip; + } + + + cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout); + if (cli->fd == -1) + return False; + + return True; +} + + +/**************************************************************************** +initialise a client structure +****************************************************************************/ +BOOL cli_initialise(struct cli_state *cli) +{ + if (cli->initialised) cli_shutdown(cli); + + memset(cli, 0, sizeof(*cli)); + cli->fd = -1; + cli->cnum = -1; + cli->pid = getpid(); + cli->mid = 1; + cli->uid = getuid(); + cli->protocol = PROTOCOL_NT1; + cli->timeout = 20000; + cli->bufsize = 0x10000; + cli->max_xmit = cli->bufsize - 4; + cli->outbuf = (char *)malloc(cli->bufsize); + cli->inbuf = (char *)malloc(cli->bufsize); + if (!cli->outbuf || !cli->inbuf) return False; + cli->initialised = 1; + return True; +} + +/**************************************************************************** +shutdown a client structure +****************************************************************************/ +void cli_shutdown(struct cli_state *cli) +{ + if (cli->outbuf) free(cli->outbuf); + if (cli->inbuf) free(cli->inbuf); +#ifdef WITH_SSL + if (cli->fd != -1) sslutil_disconnect(cli->fd); +#endif /* WITH_SSL */ + if (cli->fd != -1) close(cli->fd); + memset(cli, 0, sizeof(*cli)); +} + +/**************************************************************************** + return error codes for the last packet +****************************************************************************/ +void cli_error(struct cli_state *cli, int *eclass, int *num) +{ + *eclass = CVAL(cli->inbuf,smb_rcls); + *num = SVAL(cli->inbuf,smb_err); +} + +/**************************************************************************** +set socket options on a open connection +****************************************************************************/ +void cli_sockopt(struct cli_state *cli, char *options) +{ + set_socket_options(cli->fd, options); +} + +/**************************************************************************** +set the PID to use for smb messages. Return the old pid. +****************************************************************************/ +int cli_setpid(struct cli_state *cli, int pid) +{ + int ret = cli->pid; + cli->pid = pid; + return ret; +} + +/**************************************************************************** +establishes a connection right up to doing tconX, reading in a password. +****************************************************************************/ +BOOL cli_reestablish_connection(struct cli_state *cli) +{ + struct nmb_name calling; + struct nmb_name called; + fstring dest_host; + struct in_addr dest_ip; + fstring share; + fstring dev; + BOOL do_tcon = False; + + if (!cli->initialised || cli->fd == -1) + { + DEBUG(3,("cli_reestablish_connection: not connected\n")); + return False; + } + + /* copy the parameters necessary to re-establish the connection */ + + if (cli->cnum != 0) + { + fstrcpy(share, cli->share); + fstrcpy(dev , cli->dev); + do_tcon = True; + } + + memcpy(&called , &(cli->called ), sizeof(called )); + memcpy(&calling, &(cli->calling), sizeof(calling)); + fstrcpy(dest_host, cli->full_dest_host_name); + dest_ip = cli->dest_ip; + + DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n", + namestr(&calling), namestr(&called), inet_ntoa(dest_ip), + cli->user_name, cli->domain)); + + return cli_establish_connection(cli, + dest_host, &dest_ip, + &calling, &called, + share, dev, False, do_tcon); +} + +/**************************************************************************** +establishes a connection right up to doing tconX, reading in a password. +****************************************************************************/ +BOOL cli_establish_connection(struct cli_state *cli, + char *dest_host, struct in_addr *dest_ip, + struct nmb_name *calling, struct nmb_name *called, + char *service, char *service_type, + BOOL do_shutdown, BOOL do_tcon) +{ + DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n", + namestr(calling), namestr(called), inet_ntoa(*dest_ip), + cli->user_name, cli->domain)); + + /* establish connection */ + + if ((!cli->initialised)) + { + return False; + } + + if (cli->fd == -1) + { + if (!cli_connect(cli, dest_host, dest_ip)) + { + DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n", + namestr(calling), inet_ntoa(*dest_ip))); + return False; + } + } + + if (!cli_session_request(cli, calling, called)) + { + DEBUG(1,("failed session request\n")); + if (do_shutdown) cli_shutdown(cli); + return False; + } + + if (!cli_negprot(cli)) + { + DEBUG(1,("failed negprot\n")); + if (do_shutdown) cli_shutdown(cli); + return False; + } + + if (cli->pwd.cleartext || cli->pwd.null_pwd) + { + /* attempt clear-text session */ + + fstring passwd; + + pwd_get_cleartext(&(cli->pwd), passwd); + + /* attempt clear-text session */ + if (!cli_session_setup(cli, cli->user_name, + passwd, strlen(passwd), + NULL, 0, + cli->domain)) + { + DEBUG(1,("failed session setup\n")); + if (do_shutdown) cli_shutdown(cli); + return False; + } + if (do_tcon) + { + if (!cli_send_tconX(cli, service, service_type, + (char*)passwd, strlen(passwd))) + { + DEBUG(1,("failed tcon_X\n")); + if (do_shutdown) cli_shutdown(cli); + return False; + } + } + } + else + { + /* attempt encrypted session */ + uchar nt_sess_pwd[24]; + uchar lm_sess_pwd[24]; + + /* creates (storing a copy of) and then obtains a 24 byte password OWF */ + pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey); + pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd); + + /* attempt encrypted session */ + if (!cli_session_setup(cli, cli->user_name, + (char*)lm_sess_pwd, sizeof(lm_sess_pwd), + (char*)nt_sess_pwd, sizeof(nt_sess_pwd), + cli->domain)) + { + DEBUG(1,("failed session setup\n")); + if (do_shutdown) cli_shutdown(cli); + return False; + } + + if (do_tcon) + { + if (!cli_send_tconX(cli, service, service_type, + (char*)nt_sess_pwd, sizeof(nt_sess_pwd))) + { + DEBUG(1,("failed tcon_X\n")); + if (do_shutdown) cli_shutdown(cli); + return False; + } + } + } + + if (do_shutdown) cli_shutdown(cli); + + return True; +} diff --git a/source/libsmb/credentials.c b/source/libsmb/credentials.c new file mode 100644 index 00000000000..26d5c13bc9a --- /dev/null +++ b/source/libsmb/credentials.c @@ -0,0 +1,222 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + code to manipulate domain credentials + Copyright (C) Andrew Tridgell 1997-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; + + + +/**************************************************************************** +represent a credential as a string +****************************************************************************/ +char *credstr(uchar *cred) +{ + static fstring buf; + slprintf(buf, sizeof(buf) - 1, "%02X%02X%02X%02X%02X%02X%02X%02X", + cred[0], cred[1], cred[2], cred[3], + cred[4], cred[5], cred[6], cred[7]); + return buf; +} + + +/**************************************************************************** + setup the session key. +Input: 8 byte challenge block + 8 byte server challenge block + 16 byte md4 encrypted password +Output: + 8 byte session key +****************************************************************************/ +void cred_session_key(DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal, char *pass, + uchar session_key[8]) +{ + uint32 sum[2]; + unsigned char sum2[8]; + + sum[0] = IVAL(clnt_chal->data, 0) + IVAL(srv_chal->data, 0); + sum[1] = IVAL(clnt_chal->data, 4) + IVAL(srv_chal->data, 4); + + SIVAL(sum2,0,sum[0]); + SIVAL(sum2,4,sum[1]); + + cred_hash1(session_key, sum2,(unsigned char *)pass); + + /* debug output */ + DEBUG(4,("cred_session_key\n")); + + DEBUG(5,(" clnt_chal: %s\n", credstr(clnt_chal->data))); + DEBUG(5,(" srv_chal : %s\n", credstr(srv_chal->data))); + DEBUG(5,(" clnt+srv : %s\n", credstr(sum2))); + DEBUG(5,(" sess_key : %s\n", credstr(session_key))); +} + + +/**************************************************************************** +create a credential + +Input: + 8 byte sesssion key + 8 byte stored credential + 4 byte timestamp + +Output: + 8 byte credential +****************************************************************************/ +void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp, + DOM_CHAL *cred) +{ + DOM_CHAL time_cred; + + SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp.time); + SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4)); + + cred_hash2(cred->data, time_cred.data, session_key); + + /* debug output*/ + DEBUG(4,("cred_create\n")); + + DEBUG(5,(" sess_key : %s\n", credstr(session_key))); + DEBUG(5,(" stor_cred: %s\n", credstr(stor_cred->data))); + DEBUG(5,(" timestamp: %x\n" , timestamp.time)); + DEBUG(5,(" timecred : %s\n", credstr(time_cred.data))); + DEBUG(5,(" calc_cred: %s\n", credstr(cred->data))); +} + + +/**************************************************************************** + check a supplied credential + +Input: + 8 byte received credential + 8 byte sesssion key + 8 byte stored credential + 4 byte timestamp + +Output: + returns 1 if computed credential matches received credential + returns 0 otherwise +****************************************************************************/ +int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred, + UTIME timestamp) +{ + DOM_CHAL cred2; + + cred_create(session_key, stored_cred, timestamp, &cred2); + + /* debug output*/ + DEBUG(4,("cred_assert\n")); + + DEBUG(5,(" challenge : %s\n", credstr(cred->data))); + DEBUG(5,(" calculated: %s\n", credstr(cred2.data))); + + if (memcmp(cred->data, cred2.data, 8) == 0) + { + DEBUG(5, ("credentials check ok\n")); + return True; + } + else + { + DEBUG(5, ("credentials check wrong\n")); + return False; + } +} + + +/**************************************************************************** + checks credentials; generates next step in the credential chain +****************************************************************************/ +BOOL clnt_deal_with_creds(uchar sess_key[8], + DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred) +{ + UTIME new_clnt_time; + uint32 new_cred; + + DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__)); + + /* increment client time by one second */ + new_clnt_time.time = sto_clnt_cred->timestamp.time + 1; + + /* check that the received server credentials are valid */ + if (!cred_assert(&(rcv_srv_cred->challenge), sess_key, + &(sto_clnt_cred->challenge), new_clnt_time)) + { + return False; + } + + /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */ + new_cred = IVAL(sto_clnt_cred->challenge.data, 0); + new_cred += new_clnt_time.time; + + /* store new seed in client credentials */ + SIVAL(sto_clnt_cred->challenge.data, 0, new_cred); + + DEBUG(5,(" new clnt cred: %s\n", credstr(sto_clnt_cred->challenge.data))); + return True; +} + + +/**************************************************************************** + checks credentials; generates next step in the credential chain +****************************************************************************/ +BOOL deal_with_creds(uchar sess_key[8], + DOM_CRED *sto_clnt_cred, + DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred) +{ + UTIME new_clnt_time; + uint32 new_cred; + + DEBUG(5,("deal_with_creds: %d\n", __LINE__)); + + /* check that the received client credentials are valid */ + if (!cred_assert(&(rcv_clnt_cred->challenge), sess_key, + &(sto_clnt_cred->challenge), rcv_clnt_cred->timestamp)) + { + return False; + } + + /* increment client time by one second */ + new_clnt_time.time = rcv_clnt_cred->timestamp.time + 1; + + /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */ + new_cred = IVAL(sto_clnt_cred->challenge.data, 0); + new_cred += new_clnt_time.time; + + DEBUG(5,("deal_with_creds: new_cred[0]=%x\n", new_cred)); + + /* doesn't matter that server time is 0 */ + rtn_srv_cred->timestamp.time = 0; + + DEBUG(5,("deal_with_creds: new_clnt_time=%x\n", new_clnt_time.time)); + + /* create return credentials for inclusion in the reply */ + cred_create(sess_key, &(sto_clnt_cred->challenge), new_clnt_time, + &(rtn_srv_cred->challenge)); + + DEBUG(5,("deal_with_creds: clnt_cred=%s\n", credstr(sto_clnt_cred->challenge.data))); + + /* store new seed in client credentials */ + SIVAL(sto_clnt_cred->challenge.data, 0, new_cred); + + return True; +} + + diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c new file mode 100644 index 00000000000..f988504bba5 --- /dev/null +++ b/source/libsmb/namequery.c @@ -0,0 +1,575 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + name query routines + Copyright (C) Andrew Tridgell 1994-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "includes.h" + +extern pstring scope; +extern int DEBUGLEVEL; + +/* nmbd.c sets this to True. */ +BOOL global_in_nmbd = False; + +/**************************************************************************** +interpret a node status response +****************************************************************************/ +static void _interpret_node_status(char *p, char *master,char *rname) +{ + int numnames = CVAL(p,0); + DEBUG(1,("received %d names\n",numnames)); + + if (rname) *rname = 0; + if (master) *master = 0; + + p += 1; + while (numnames--) + { + char qname[17]; + int type; + fstring flags; + int i; + *flags = 0; + StrnCpy(qname,p,15); + type = CVAL(p,15); + p += 16; + + fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " "); + if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B "); + if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P "); + if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M "); + if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H "); + if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> "); + if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> "); + if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> "); + if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> "); + + if (master && !*master && type == 0x1d) { + StrnCpy(master,qname,15); + trim_string(master,NULL," "); + } + + if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) { + StrnCpy(rname,qname,15); + trim_string(rname,NULL," "); + } + + for (i = strlen( qname) ; --i >= 0 ; ) { + if (!isprint((int)qname[i])) qname[i] = '.'; + } + DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags)); + p+=2; + } + DEBUG(1,("num_good_sends=%d num_good_receives=%d\n", + IVAL(p,20),IVAL(p,24))); +} + + +/**************************************************************************** + do a netbios name status query on a host + + the "master" parameter is a hack used for finding workgroups. + **************************************************************************/ +BOOL name_status(int fd,char *name,int name_type,BOOL recurse, + struct in_addr to_ip,char *master,char *rname, + void (*fn)(struct packet_struct *)) +{ + BOOL found=False; + int retries = 2; + int retry_time = 5000; + struct timeval tval; + struct packet_struct p; + struct packet_struct *p2; + struct nmb_packet *nmb = &p.packet.nmb; + static int name_trn_id = 0; + + bzero((char *)&p,sizeof(p)); + + if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + + ((unsigned)getpid()%(unsigned)100); + name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; + + nmb->header.name_trn_id = name_trn_id; + nmb->header.opcode = 0; + nmb->header.response = False; + nmb->header.nm_flags.bcast = False; + nmb->header.nm_flags.recursion_available = False; + nmb->header.nm_flags.recursion_desired = False; + nmb->header.nm_flags.trunc = False; + nmb->header.nm_flags.authoritative = False; + nmb->header.rcode = 0; + nmb->header.qdcount = 1; + nmb->header.ancount = 0; + nmb->header.nscount = 0; + nmb->header.arcount = 0; + + make_nmb_name(&nmb->question.question_name,name,name_type,scope); + + nmb->question.question_type = 0x21; + nmb->question.question_class = 0x1; + + p.ip = to_ip; + p.port = NMB_PORT; + p.fd = fd; + p.timestamp = time(NULL); + p.packet_type = NMB_PACKET; + + GetTimeOfDay(&tval); + + if (!send_packet(&p)) + return(False); + + retries--; + + while (1) + { + struct timeval tval2; + GetTimeOfDay(&tval2); + if (TvalDiff(&tval,&tval2) > retry_time) { + if (!retries) break; + if (!found && !send_packet(&p)) + return False; + GetTimeOfDay(&tval); + retries--; + } + + if ((p2=receive_packet(fd,NMB_PACKET,90))) + { + struct nmb_packet *nmb2 = &p2->packet.nmb; + debug_nmb_packet(p2); + + if (nmb->header.name_trn_id != nmb2->header.name_trn_id || + !nmb2->header.response) { + /* its not for us - maybe deal with it later */ + if (fn) + fn(p2); + else + free_packet(p2); + continue; + } + + if (nmb2->header.opcode != 0 || + nmb2->header.nm_flags.bcast || + nmb2->header.rcode || + !nmb2->header.ancount || + nmb2->answers->rr_type != 0x21) { + /* XXXX what do we do with this? could be a redirect, but + we'll discard it for the moment */ + free_packet(p2); + continue; + } + + _interpret_node_status(&nmb2->answers->rdata[0], master,rname); + free_packet(p2); + return(True); + } + } + + + DEBUG(0,("No status response (this is not unusual)\n")); + + return(False); +} + + +/**************************************************************************** + do a netbios name query to find someones IP + returns an array of IP addresses or NULL if none + *count will be set to the number of addresses returned + ****************************************************************************/ +struct in_addr *name_query(int fd,char *name,int name_type, BOOL bcast,BOOL recurse, + struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *)) +{ + BOOL found=False; + int i, retries = 3; + int retry_time = bcast?250:2000; + struct timeval tval; + struct packet_struct p; + struct packet_struct *p2; + struct nmb_packet *nmb = &p.packet.nmb; + static int name_trn_id = 0; + struct in_addr *ip_list = NULL; + + bzero((char *)&p,sizeof(p)); + (*count) = 0; + + if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + + ((unsigned)getpid()%(unsigned)100); + name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; + + nmb->header.name_trn_id = name_trn_id; + nmb->header.opcode = 0; + nmb->header.response = False; + nmb->header.nm_flags.bcast = bcast; + nmb->header.nm_flags.recursion_available = False; + nmb->header.nm_flags.recursion_desired = recurse; + nmb->header.nm_flags.trunc = False; + nmb->header.nm_flags.authoritative = False; + nmb->header.rcode = 0; + nmb->header.qdcount = 1; + nmb->header.ancount = 0; + nmb->header.nscount = 0; + nmb->header.arcount = 0; + + make_nmb_name(&nmb->question.question_name,name,name_type,scope); + + nmb->question.question_type = 0x20; + nmb->question.question_class = 0x1; + + p.ip = to_ip; + p.port = NMB_PORT; + p.fd = fd; + p.timestamp = time(NULL); + p.packet_type = NMB_PACKET; + + GetTimeOfDay(&tval); + + if (!send_packet(&p)) + return NULL; + + retries--; + + while (1) + { + struct timeval tval2; + GetTimeOfDay(&tval2); + if (TvalDiff(&tval,&tval2) > retry_time) { + if (!retries) break; + if (!found && !send_packet(&p)) + return NULL; + GetTimeOfDay(&tval); + retries--; + } + + if ((p2=receive_packet(fd,NMB_PACKET,90))) + { + struct nmb_packet *nmb2 = &p2->packet.nmb; + debug_nmb_packet(p2); + + if (nmb->header.name_trn_id != nmb2->header.name_trn_id || + !nmb2->header.response) { + /* its not for us - maybe deal with it later + (put it on the queue?) */ + if (fn) + fn(p2); + else + free_packet(p2); + continue; + } + + if (nmb2->header.opcode != 0 || + nmb2->header.nm_flags.bcast || + nmb2->header.rcode || + !nmb2->header.ancount) { + /* XXXX what do we do with this? could be a redirect, but + we'll discard it for the moment */ + free_packet(p2); + continue; + } + + ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) * + ((*count)+nmb2->answers->rdlength/6)); + if (ip_list) { + DEBUG(fn?3:2,("Got a positive name query response from %s ( ", + inet_ntoa(p2->ip))); + for (i=0;i<nmb2->answers->rdlength/6;i++) { + putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]); + DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)]))); + (*count)++; + } + DEBUG(fn?3:2,(")\n")); + } + found=True; retries=0; + free_packet(p2); + if (fn) break; + } + } + + return ip_list; +} + +/******************************************************** + Start parsing the lmhosts file. +*********************************************************/ + +FILE *startlmhosts(char *fname) +{ + FILE *fp = fopen(fname,"r"); + if (!fp) { + DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n", + fname, strerror(errno))); + return NULL; + } + return fp; +} + +/******************************************************** + Parse the next line in the lmhosts file. +*********************************************************/ + +BOOL getlmhostsent( FILE *fp, char *name, int *name_type, struct in_addr *ipaddr) +{ + pstring line; + + while(!feof(fp) && !ferror(fp)) { + pstring ip,flags,extra; + char *ptr; + int count = 0; + + *name_type = -1; + + if (!fgets_slash(line,sizeof(pstring),fp)) + continue; + + if (*line == '#') + continue; + + pstrcpy(ip,""); + pstrcpy(name,""); + pstrcpy(flags,""); + + ptr = line; + + if (next_token(&ptr,ip ,NULL,sizeof(ip))) + ++count; + if (next_token(&ptr,name ,NULL, sizeof(name))) + ++count; + if (next_token(&ptr,flags,NULL, sizeof(flags))) + ++count; + if (next_token(&ptr,extra,NULL, sizeof(extra))) + ++count; + + if (count <= 0) + continue; + + if (count > 0 && count < 2) + { + DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line)); + continue; + } + + if (count >= 4) + { + DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n")); + continue; + } + + DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags)); + + if (strchr(flags,'G') || strchr(flags,'S')) + { + DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n")); + continue; + } + + *ipaddr = *interpret_addr2(ip); + + /* Extra feature. If the name ends in '#XX', where XX is a hex number, + then only add that name type. */ + if((ptr = strchr(name, '#')) != NULL) + { + char *endptr; + + ptr++; + *name_type = (int)strtol(ptr, &endptr,0); + + if(!*ptr || (endptr == ptr)) + { + DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name)); + continue; + } + + *(--ptr) = '\0'; /* Truncate at the '#' */ + } + + return True; + } + + return False; +} + +/******************************************************** + Finish parsing the lmhosts file. +*********************************************************/ + +void endlmhosts(FILE *fp) +{ + fclose(fp); +} + +/******************************************************** + Resolve a name into an IP address. Use this function if + the string is either an IP address, DNS or host name + or NetBIOS name. This uses the name switch in the + smb.conf to determine the order of name resolution. +*********************************************************/ + +BOOL resolve_name(char *name, struct in_addr *return_ip) +{ + int i; + BOOL pure_address = True; + pstring name_resolve_list; + fstring tok; + char *ptr; + + if (strcmp(name,"0.0.0.0") == 0) { + return_ip->s_addr = 0; + return True; + } + if (strcmp(name,"255.255.255.255") == 0) { + return_ip->s_addr = 0xFFFFFFFF; + return True; + } + + for (i=0; pure_address && name[i]; i++) + if (!(isdigit((int)name[i]) || name[i] == '.')) + pure_address = False; + + /* if it's in the form of an IP address then get the lib to interpret it */ + if (pure_address) { + return_ip->s_addr = inet_addr(name); + return True; + } + + pstrcpy(name_resolve_list, lp_name_resolve_order()); + ptr = name_resolve_list; + if (!ptr || !*ptr) ptr = "host"; + + while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) { + if(strequal(tok, "host") || strequal(tok, "hosts")) { + + /* + * "host" means do a localhost, or dns lookup. + */ + + struct hostent *hp; + + DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name)); + + if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) { + putip((char *)return_ip,(char *)hp->h_addr); + return True; + } + + } else if(strequal( tok, "lmhosts")) { + + /* + * "lmhosts" means parse the local lmhosts file. + */ + + FILE *fp; + pstring lmhost_name; + int name_type; + + DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name)); + + fp = startlmhosts( LMHOSTSFILE ); + if(fp) { + while( getlmhostsent(fp, lmhost_name, &name_type, return_ip ) ) { + if( strequal(name, lmhost_name )) { + endlmhosts(fp); + return True; + } + } + endlmhosts(fp); + } + + } else if(strequal( tok, "wins")) { + + int sock; + + /* + * "wins" means do a unicast lookup to the WINS server. + * Ignore if there is no WINS server specified or if the + * WINS server is one of our interfaces (if we're being + * called from within nmbd - we can't do this call as we + * would then block). + */ + + DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name)); + + if(*lp_wins_server()) { + struct in_addr wins_ip = *interpret_addr2(lp_wins_server()); + BOOL wins_ismyip = ismyip(wins_ip); + + if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) { + sock = open_socket_in( SOCK_DGRAM, 0, 3, + interpret_addr(lp_socket_address()) ); + + if (sock != -1) { + struct in_addr *iplist = NULL; + int count; + iplist = name_query(sock, name, 0x20, False, True, wins_ip, &count, NULL); + if(iplist != NULL) { + *return_ip = iplist[0]; + free((char *)iplist); + close(sock); + return True; + } + close(sock); + } + } + } else { + DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n")); + } + } else if(strequal( tok, "bcast")) { + + int sock; + + /* + * "bcast" means do a broadcast lookup on all the local interfaces. + */ + + DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name)); + + sock = open_socket_in( SOCK_DGRAM, 0, 3, + interpret_addr(lp_socket_address()) ); + + if (sock != -1) { + struct in_addr *iplist = NULL; + int count; + int num_interfaces = iface_count(); + set_socket_options(sock,"SO_BROADCAST"); + /* + * Lookup the name on all the interfaces, return on + * the first successful match. + */ + for( i = 0; i < num_interfaces; i++) { + struct in_addr sendto_ip; + /* Done this way to fix compiler error on IRIX 5.x */ + sendto_ip = *iface_bcast(*iface_n_ip(i)); + iplist = name_query(sock, name, 0x20, True, False, sendto_ip, &count, NULL); + if(iplist != NULL) { + *return_ip = iplist[0]; + free((char *)iplist); + close(sock); + return True; + } + } + close(sock); + } + + } else { + DEBUG(0,("resolve_name: unknown name switch type %s\n", tok)); + } + } + + return False; +} diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c index 67432271737..d08003133f1 100644 --- a/source/libsmb/nmblib.c +++ b/source/libsmb/nmblib.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. NBT netbios library routines - Copyright (C) Andrew Tridgell 1994-1995 + Copyright (C) Andrew Tridgell 1994-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,15 +21,134 @@ */ #include "includes.h" -#include "nameserv.h" extern int DEBUGLEVEL; -int num_good_sends=0; -int num_good_receives=0; -static uint16 name_trn_id = 0; -BOOL CanRecurse = True; -extern pstring scope; +int num_good_sends = 0; +int num_good_receives = 0; + +static struct opcode_names { + char *nmb_opcode_name; + int opcode; +} nmb_header_opcode_names[] = { + {"Query", 0 }, + {"Registration", 5 }, + {"Release", 6 }, + {"WACK", 7 }, + {"Refresh", 8 }, + {"Refresh(altcode)", 9 }, + {"Multi-homed Registration", 15 }, + {0, -1 } +}; + +/**************************************************************************** + * Lookup a nmb opcode name. + ****************************************************************************/ +static char *lookup_opcode_name( int opcode ) +{ + struct opcode_names *op_namep; + int i; + + for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) { + op_namep = &nmb_header_opcode_names[i]; + if(opcode == op_namep->opcode) + return op_namep->nmb_opcode_name; + } + return "<unknown opcode>"; +} + +/**************************************************************************** + print out a res_rec structure + ****************************************************************************/ +static void debug_nmb_res_rec(struct res_rec *res, char *hdr) +{ + int i, j; + + DEBUGADD( 4, ( " %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n", + hdr, + namestr(&res->rr_name), + res->rr_type, + res->rr_class, + res->ttl ) ); + + if( res->rdlength == 0 || res->rdata == NULL ) + return; + + for (i = 0; i < res->rdlength; i+= 16) + { + DEBUGADD(4, (" %s %3x char ", hdr, i)); + + for (j = 0; j < 16; j++) + { + unsigned char x = res->rdata[i+j]; + if (x < 32 || x > 127) x = '.'; + + if (i+j >= res->rdlength) break; + DEBUGADD(4, ("%c", x)); + } + + DEBUGADD(4, (" hex ")); + + for (j = 0; j < 16; j++) + { + if (i+j >= res->rdlength) break; + DEBUGADD(4, ("%02X", (unsigned char)res->rdata[i+j])); + } + + DEBUGADD(4, ("\n")); + } +} + +/**************************************************************************** + process a nmb packet + ****************************************************************************/ +void debug_nmb_packet(struct packet_struct *p) +{ + struct nmb_packet *nmb = &p->packet.nmb; + + if( DEBUGLVL( 4 ) ) + { + dbgtext( "nmb packet from %s(%d) header: id=%d opcode=%s(%d) response=%s\n", + inet_ntoa(p->ip), p->port, + nmb->header.name_trn_id, + lookup_opcode_name(nmb->header.opcode), + nmb->header.opcode, + BOOLSTR(nmb->header.response) ); + dbgtext( " header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n", + BOOLSTR(nmb->header.nm_flags.bcast), + BOOLSTR(nmb->header.nm_flags.recursion_available), + BOOLSTR(nmb->header.nm_flags.recursion_desired), + BOOLSTR(nmb->header.nm_flags.trunc), + BOOLSTR(nmb->header.nm_flags.authoritative) ); + dbgtext( " header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n", + nmb->header.rcode, + nmb->header.qdcount, + nmb->header.ancount, + nmb->header.nscount, + nmb->header.arcount ); + } + + if (nmb->header.qdcount) + { + DEBUGADD( 4, ( " question: q_name=%s q_type=%d q_class=%d\n", + namestr(&nmb->question.question_name), + nmb->question.question_type, + nmb->question.question_class) ); + } + + if (nmb->answers && nmb->header.ancount) + { + debug_nmb_res_rec(nmb->answers,"answers"); + } + if (nmb->nsrecs && nmb->header.nscount) + { + debug_nmb_res_rec(nmb->nsrecs,"nsrecs"); + } + if (nmb->additional && nmb->header.arcount) + { + debug_nmb_res_rec(nmb->additional,"additional"); + } +} /******************************************************************* handle "compressed" name pointers @@ -38,7 +157,7 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length, BOOL *got_pointer,int *ret) { int loop_count=0; - + while ((ubuf[*offset] & 0xC0) == 0xC0) { if (!*got_pointer) (*ret) += 2; (*got_pointer)=True; @@ -54,8 +173,7 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length, parse a nmb name from "compressed" format to something readable return the space taken by the name, or 0 if the name is invalid ******************************************************************/ -static int parse_nmb_name(char *inbuf,int offset,int length, - struct nmb_name *name) +static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *name) { int m,n=0; unsigned char *ubuf = (unsigned char *)inbuf; @@ -81,7 +199,7 @@ static int parse_nmb_name(char *inbuf,int offset,int length, unsigned char c1,c2; c1 = ubuf[offset++]-'A'; c2 = ubuf[offset++]-'A'; - if ((c1 & 0xF0) || (c2 & 0xF0)) return(0); + if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1)) return(0); name->name[n++] = (c1<<4) | c2; m -= 2; } @@ -90,7 +208,7 @@ static int parse_nmb_name(char *inbuf,int offset,int length, if (n==16) { /* parse out the name type, its always in the 16th byte of the name */ - name->name_type = name->name[15]; + name->name_type = ((unsigned char)name->name[15]) & 0xff; /* remove trailing spaces */ name->name[15] = 0; @@ -134,8 +252,9 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name) /* special case for wildcard name */ bzero(buf1,20); buf1[0] = '*'; + buf1[15] = name->name_type; } else { - sprintf(buf1,"%-15.15s%c",name->name,name->name_type); + slprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type); } buf[offset] = 0x20; @@ -153,7 +272,7 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name) if (name->scope[0]) { /* XXXX this scope handling needs testing */ ret += strlen(name->scope) + 1; - strcpy(&buf[offset+1],name->scope); + pstrcpy(&buf[offset+1],name->scope); p = &buf[offset+1]; while ((p = strchr(p,'.'))) { @@ -177,20 +296,19 @@ char *namestr(struct nmb_name *n) char *p = ret[i]; if (!n->scope[0]) - sprintf(p,"%s(%x)",n->name,n->name_type); + slprintf(p,sizeof(fstring)-1, "%s<%02x>",n->name,n->name_type); else - sprintf(p,"%s(%x).%s",n->name,n->name_type,n->scope); + slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",n->name,n->name_type,n->scope); i = (i+1)%4; return(p); } /******************************************************************* - allocate are parse some resource records + allocate and parse some resource records ******************************************************************/ static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length, - struct res_rec **recs, - int count) + struct res_rec **recs, int count) { int i; *recs = (struct res_rec *)malloc(sizeof(**recs)*count); @@ -246,6 +364,27 @@ static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count) } /******************************************************************* + put a compressed name pointer record into a packet + ******************************************************************/ +static int put_compressed_name_ptr(unsigned char *buf,int offset,struct res_rec *rec,int ptr_offset) +{ + int ret=0; + buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF)); + buf[offset+1] = (ptr_offset & 0xFF); + offset += 2; + ret += 2; + RSSVAL(buf,offset,rec->rr_type); + RSSVAL(buf,offset+2,rec->rr_class); + RSIVAL(buf,offset+4,rec->ttl); + RSSVAL(buf,offset+8,rec->rdlength); + memcpy(buf+offset+10,rec->rdata,rec->rdlength); + offset += 10+rec->rdlength; + ret += 10+rec->rdlength; + + return(ret); +} + +/******************************************************************* parse a dgram packet. Return False if the packet can't be parsed or is invalid for some reason, True otherwise @@ -304,6 +443,9 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb) /* parse the header */ nmb->header.name_trn_id = RSVAL(inbuf,0); + + DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id)); + nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF; nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False; nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4); @@ -311,7 +453,7 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb) nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False; nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False; nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False; - nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False; + nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False; nmb->header.rcode = CVAL(inbuf,3) & 0xF; nmb->header.qdcount = RSVAL(inbuf,4); nmb->header.ancount = RSVAL(inbuf,6); @@ -351,9 +493,119 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb) } /******************************************************************* + 'Copy constructor' for an nmb packet + ******************************************************************/ +static struct packet_struct *copy_nmb_packet(struct packet_struct *packet) +{ + struct nmb_packet *nmb; + struct nmb_packet *copy_nmb; + struct packet_struct *pkt_copy; + + if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL) + { + DEBUG(0,("copy_nmb_packet: malloc fail.\n")); + return NULL; + } + + /* Structure copy of entire thing. */ + + *pkt_copy = *packet; + + /* Ensure this copy is not locked. */ + pkt_copy->locked = False; + + /* Ensure this copy has no resource records. */ + nmb = &packet->packet.nmb; + copy_nmb = &pkt_copy->packet.nmb; + + copy_nmb->answers = NULL; + copy_nmb->nsrecs = NULL; + copy_nmb->additional = NULL; + + /* Now copy any resource records. */ + + if (nmb->answers) + { + if((copy_nmb->answers = (struct res_rec *) + malloc(nmb->header.ancount * sizeof(struct res_rec))) == NULL) + goto free_and_exit; + memcpy((char *)copy_nmb->answers, (char *)nmb->answers, + nmb->header.ancount * sizeof(struct res_rec)); + } + if (nmb->nsrecs) + { + if((copy_nmb->nsrecs = (struct res_rec *) + malloc(nmb->header.nscount * sizeof(struct res_rec))) == NULL) + goto free_and_exit; + memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs, + nmb->header.nscount * sizeof(struct res_rec)); + } + if (nmb->additional) + { + if((copy_nmb->additional = (struct res_rec *) + malloc(nmb->header.arcount * sizeof(struct res_rec))) == NULL) + goto free_and_exit; + memcpy((char *)copy_nmb->additional, (char *)nmb->additional, + nmb->header.arcount * sizeof(struct res_rec)); + } + + return pkt_copy; + +free_and_exit: + + if(copy_nmb->answers) + free((char *)copy_nmb->answers); + if(copy_nmb->nsrecs) + free((char *)copy_nmb->nsrecs); + if(copy_nmb->additional) + free((char *)copy_nmb->additional); + free((char *)pkt_copy); + + DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n")); + return NULL; +} + +/******************************************************************* + 'Copy constructor' for a dgram packet + ******************************************************************/ +static struct packet_struct *copy_dgram_packet(struct packet_struct *packet) +{ + struct packet_struct *pkt_copy; + + if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL) + { + DEBUG(0,("copy_dgram_packet: malloc fail.\n")); + return NULL; + } + + /* Structure copy of entire thing. */ + + *pkt_copy = *packet; + + /* Ensure this copy is not locked. */ + pkt_copy->locked = False; + + /* There are no additional pointers in a dgram packet, + we are finished. */ + return pkt_copy; +} + +/******************************************************************* + 'Copy constructor' for a generic packet + ******************************************************************/ +struct packet_struct *copy_packet(struct packet_struct *packet) +{ + if(packet->packet_type == NMB_PACKET) + return copy_nmb_packet(packet); + else if (packet->packet_type == DGRAM_PACKET) + return copy_dgram_packet(packet); + return NULL; +} + +/******************************************************************* free up any resources associated with an nmb packet ******************************************************************/ -void free_nmb_packet(struct nmb_packet *nmb) +static void free_nmb_packet(struct nmb_packet *nmb) { if (nmb->answers) free(nmb->answers); if (nmb->nsrecs) free(nmb->nsrecs); @@ -361,12 +613,24 @@ void free_nmb_packet(struct nmb_packet *nmb) } /******************************************************************* + free up any resources associated with a dgram packet + ******************************************************************/ +static void free_dgram_packet(struct dgram_packet *nmb) +{ + /* We have nothing to do for a dgram packet. */ +} + +/******************************************************************* free up any resources associated with a packet ******************************************************************/ void free_packet(struct packet_struct *packet) { + if (packet->locked) + return; if (packet->packet_type == NMB_PACKET) free_nmb_packet(&packet->packet.nmb); + else if (packet->packet_type == DGRAM_PACKET) + free_dgram_packet(&packet->packet.dgram); free(packet); } @@ -382,7 +646,7 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type) char buf[MAX_DGRAM_SIZE]; int length; BOOL ok=False; - + length = read_udp_socket(fd,buf,sizeof(buf)); if (length < MIN_DGRAM_SIZE) return(NULL); @@ -394,6 +658,7 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type) packet->ip = lastip; packet->port = lastport; packet->fd = fd; + packet->locked = False; packet->timestamp = time(NULL); packet->packet_type = packet_type; switch (packet_type) @@ -407,14 +672,16 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type) break; } if (!ok) { + DEBUG(10,("parse_nmb: discarding packet id = %d\n", + packet->packet.nmb.header.name_trn_id)); free(packet); return(NULL); } num_good_receives++; - DEBUG(4,("%s received a packet of len %d from (%s) port %d\n", - timestring(),length,inet_ntoa(packet->ip),packet->port)); + DEBUG(5,("Received a packet of len %d from (%s) port %d\n", + length, inet_ntoa(packet->ip), packet->port ) ); return(packet); } @@ -434,8 +701,8 @@ static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port) sock_out.sin_port = htons( port ); sock_out.sin_family = AF_INET; - DEBUG(4,("%s sending a packet of len %d to (%s) on port %d\n", - timestring(),len,inet_ntoa(ip),port)); + DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n", + len, inet_ntoa(ip), port ) ); ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0); @@ -494,15 +761,27 @@ static int build_dgram(char *buf,struct packet_struct *p) /******************************************************************* build a nmb name - ******************************************************************/ -void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope) + *******************************************************************/ +void make_nmb_name( struct nmb_name *n, char *name, int type, char *this_scope ) { - strcpy(n->name,name); - strupper(n->name); - n->name_type = type; - strcpy(n->scope,this_scope); + memset( (char *)n, '\0', sizeof(struct nmb_name) ); + StrnCpy( n->name, name, 15 ); + strupper( n->name ); + n->name_type = (unsigned int)type & 0xFF; + StrnCpy( n->scope, this_scope, 63 ); + strupper( n->scope ); } +/******************************************************************* + Compare two nmb names + ******************************************************************/ + +BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2) +{ + return ((n1->name_type == n2->name_type) && + strequal(n1->name ,n2->name ) && + strequal(n1->scope,n2->scope)); +} /******************************************************************* build a nmb packet ready for sending @@ -522,12 +801,15 @@ static int build_nmb(char *buf,struct packet_struct *p) RSSVAL(ubuf,offset,nmb->header.name_trn_id); ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3; if (nmb->header.response) ubuf[offset+2] |= (1<<7); - if (nmb->header.nm_flags.authoritative) ubuf[offset+2] |= 0x4; + if (nmb->header.nm_flags.authoritative && + nmb->header.response) ubuf[offset+2] |= 0x4; if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2; if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1; - if (nmb->header.nm_flags.recursion_available) ubuf[offset+3] |= 0x80; + if (nmb->header.nm_flags.recursion_available && + nmb->header.response) ubuf[offset+3] |= 0x80; if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10; ubuf[offset+3] |= (nmb->header.rcode & 0xF); + RSSVAL(ubuf,offset+4,nmb->header.qdcount); RSSVAL(ubuf,offset+6,nmb->header.ancount); RSSVAL(ubuf,offset+8,nmb->header.nscount); @@ -550,10 +832,27 @@ static int build_nmb(char *buf,struct packet_struct *p) offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs, nmb->header.nscount); - if (nmb->header.arcount) + /* + * The spec says we must put compressed name pointers + * in the following outgoing packets : + * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST, + * NAME_RELEASE_REQUEST. + */ + + if((nmb->header.response == False) && + ((nmb->header.opcode == NMB_NAME_REG_OPCODE) || + (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) || + (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) || + (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) || + (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) && + (nmb->header.arcount == 1)) { + + offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12); + + } else if (nmb->header.arcount) { offset += put_res_rec((char *)ubuf,offset,nmb->additional, nmb->header.arcount); - + } return(offset); } @@ -572,6 +871,7 @@ BOOL send_packet(struct packet_struct *p) { case NMB_PACKET: len = build_nmb(buf,p); + debug_nmb_packet(p); break; case DGRAM_PACKET: @@ -598,7 +898,7 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t) timeout.tv_sec = t/1000; timeout.tv_usec = 1000*(t%1000); - sys_select(&fds,&timeout); + sys_select(fd+1,&fds,&timeout); if (FD_ISSET(fd,&fds)) return(read_packet(fd,type)); @@ -608,329 +908,46 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t) /**************************************************************************** -interpret a node status response -****************************************************************************/ -static void interpret_node_status(char *p, char *master,char *rname) -{ - int level = (master||rname)?4:0; - int numnames = CVAL(p,0); - DEBUG(level,("received %d names\n",numnames)); - - if (rname) *rname = 0; - if (master) *master = 0; - - p += 1; - while (numnames--) - { - char qname[17]; - int type; - fstring flags; - *flags = 0; - StrnCpy(qname,p,15); - type = CVAL(p,15); - p += 16; - - if (p[0] & 0x80) strcat(flags,"<GROUP> "); - if ((p[0] & 0x60) == 0) strcat(flags,"B "); - if ((p[0] & 0x60) == 1) strcat(flags,"P "); - if ((p[0] & 0x60) == 2) strcat(flags,"M "); - if ((p[0] & 0x60) == 3) strcat(flags,"_ "); - if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> "); - if (p[0] & 0x08) strcat(flags,"<CONFLICT> "); - if (p[0] & 0x04) strcat(flags,"<ACTIVE> "); - if (p[0] & 0x02) strcat(flags,"<PERMANENT> "); - - if (master && !*master && type == 0x1d) { - StrnCpy(master,qname,15); - trim_string(master,NULL," "); - } - - if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) { - StrnCpy(rname,qname,15); - trim_string(rname,NULL," "); - } - - DEBUG(level,("\t%s (type=0x%x)\t%s\n",qname,type,flags)); - p+=2; - } - DEBUG(level,("num_good_sends=%d num_good_receives=%d\n", - IVAL(p,20),IVAL(p,24))); -} - - -/**************************************************************************** - do a netbios name status query on a host - - the "master" parameter is a hack used for finding workgroups. - **************************************************************************/ -BOOL name_status(int fd,char *name,int name_type,BOOL recurse, - struct in_addr to_ip,char *master,char *rname, - void (*fn)()) +return the number of bits that match between two 4 character buffers + ***************************************************************************/ +static int matching_bits(uchar *p1, uchar *p2) { - BOOL found=False; - int retries = 2; - int retry_time = 5000; - struct timeval tval; - struct packet_struct p; - struct packet_struct *p2; - struct nmb_packet *nmb = &p.packet.nmb; - - bzero((char *)&p,sizeof(p)); - - if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) + - (getpid()%(unsigned)100); - name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; - - nmb->header.name_trn_id = name_trn_id; - nmb->header.opcode = 0; - nmb->header.response = False; - nmb->header.nm_flags.bcast = False; - nmb->header.nm_flags.recursion_available = CanRecurse; - nmb->header.nm_flags.recursion_desired = recurse; - nmb->header.nm_flags.trunc = False; - nmb->header.nm_flags.authoritative = False; - nmb->header.rcode = 0; - nmb->header.qdcount = 1; - nmb->header.ancount = 0; - nmb->header.nscount = 0; - nmb->header.arcount = 0; - - make_nmb_name(&nmb->question.question_name,name,name_type,scope); - - nmb->question.question_type = 0x21; - nmb->question.question_class = 0x1; - - p.ip = to_ip; - p.port = NMB_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = NMB_PACKET; - - GetTimeOfDay(&tval); - - if (!send_packet(&p)) - return(False); - - retries--; - - while (1) - { - struct timeval tval2; - GetTimeOfDay(&tval2); - if (TvalDiff(&tval,&tval2) > retry_time) { - if (!retries) break; - if (!found && !send_packet(&p)) - return False; - GetTimeOfDay(&tval); - retries--; - } - - if ((p2=receive_packet(fd,NMB_PACKET,90))) - { - struct nmb_packet *nmb2 = &p2->packet.nmb; - if (nmb->header.name_trn_id != nmb2->header.name_trn_id || - !nmb2->header.response) { - /* its not for us - maybe deal with it later */ - if (fn) - fn(p2); - else - free_packet(p2); - continue; - } - - if (nmb2->header.opcode != 0 || - nmb2->header.nm_flags.bcast || - nmb2->header.rcode || - !nmb2->header.ancount || - nmb2->answers->rr_type != 0x21) { - /* XXXX what do we do with this? could be a redirect, but - we'll discard it for the moment */ - free_packet(p2); - continue; - } - - interpret_node_status(&nmb2->answers->rdata[0], master,rname); - free_packet(p2); - return(True); + int i, j, ret = 0; + for (i=0; i<4; i++) { + if (p1[i] != p2[i]) break; + ret += 8; } - } - - DEBUG(0,("No status response (this is not unusual)\n")); + if (i==4) return ret; - return(False); + for (j=0; j<8; j++) { + if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j)))) break; + ret++; + } + + return ret; } +static uchar sort_ip[4]; + /**************************************************************************** - do a netbios name query to find someones IP - ****************************************************************************/ -BOOL name_query(int fd,char *name,int name_type, - BOOL bcast,BOOL recurse, - struct in_addr to_ip, struct in_addr *ip,void (*fn)()) +compare two query reply records + ***************************************************************************/ +static int name_query_comp(uchar *p1, uchar *p2) { - BOOL found=False; - int retries = 3; - int retry_time = bcast?250:2000; - struct timeval tval; - struct packet_struct p; - struct packet_struct *p2; - struct nmb_packet *nmb = &p.packet.nmb; - - bzero((char *)&p,sizeof(p)); - - if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) + - (getpid()%(unsigned)100); - name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; - - nmb->header.name_trn_id = name_trn_id; - nmb->header.opcode = 0; - nmb->header.response = False; - nmb->header.nm_flags.bcast = bcast; - nmb->header.nm_flags.recursion_available = CanRecurse; - nmb->header.nm_flags.recursion_desired = recurse; - nmb->header.nm_flags.trunc = False; - nmb->header.nm_flags.authoritative = False; - nmb->header.rcode = 0; - nmb->header.qdcount = 1; - nmb->header.ancount = 0; - nmb->header.nscount = 0; - nmb->header.arcount = 0; - - make_nmb_name(&nmb->question.question_name,name,name_type,scope); - - nmb->question.question_type = 0x20; - nmb->question.question_class = 0x1; - - p.ip = to_ip; - p.port = NMB_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = NMB_PACKET; - - GetTimeOfDay(&tval); - - if (!send_packet(&p)) - return(False); - - retries--; - - while (1) - { - struct timeval tval2; - GetTimeOfDay(&tval2); - if (TvalDiff(&tval,&tval2) > retry_time) { - if (!retries) break; - if (!found && !send_packet(&p)) - return False; - GetTimeOfDay(&tval); - retries--; - } - - if ((p2=receive_packet(fd,NMB_PACKET,90))) - { - struct nmb_packet *nmb2 = &p2->packet.nmb; - if (nmb->header.name_trn_id != nmb2->header.name_trn_id || - !nmb2->header.response) { - /* its not for us - maybe deal with it later - (put it on the queue?) */ - if (fn) - fn(p2); - else - free_packet(p2); - continue; - } - - if (nmb2->header.opcode != 0 || - nmb2->header.nm_flags.bcast || - nmb2->header.rcode || - !nmb2->header.ancount) { - /* XXXX what do we do with this? could be a redirect, but - we'll discard it for the moment */ - free_packet(p2); - continue; - } - - if (ip) { - putip((char *)ip,&nmb2->answers->rdata[2]); - DEBUG(fn?3:2,("Got a positive name query response from %s", - inet_ntoa(p2->ip))); - DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip))); - } - found=True; retries=0; - free_packet(p2); - if (fn) break; - } - } - - return(found); + return matching_bits(p2+2, sort_ip) - matching_bits(p1+2, sort_ip); } - /**************************************************************************** - construct and send a netbios DGRAM - - Note that this currently sends all answers to port 138. thats the - wrong things to do! I should send to the requestors port. XXX - **************************************************************************/ -BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len, - char *srcname,char *dstname, - int src_type,int dest_type, - struct in_addr dest_ip, - struct in_addr src_ip) +sort a set of 6 byte name query response records so that the IPs that +have the most leading bits in common with the specified address come first + ***************************************************************************/ +void sort_query_replies(char *data, int n, struct in_addr ip) { - struct packet_struct p; - struct dgram_packet *dgram = &p.packet.dgram; - char *ptr,*p2; - char tmp[4]; - - bzero((char *)&p,sizeof(p)); - - dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */ - dgram->header.flags.node_type = M_NODE; - dgram->header.flags.first = True; - dgram->header.flags.more = False; - dgram->header.dgm_id = name_trn_id++; - dgram->header.source_ip = src_ip; - dgram->header.source_port = DGRAM_PORT; - dgram->header.dgm_length = 0; /* let build_dgram() handle this */ - dgram->header.packet_offset = 0; - - make_nmb_name(&dgram->source_name,srcname,src_type,scope); - make_nmb_name(&dgram->dest_name,dstname,dest_type,scope); - - ptr = &dgram->data[0]; - - /* now setup the smb part */ - ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */ - memcpy(tmp,ptr,4); - set_message(ptr,17,17 + len,True); - memcpy(ptr,tmp,4); - - CVAL(ptr,smb_com) = SMBtrans; - SSVAL(ptr,smb_vwv1,len); - SSVAL(ptr,smb_vwv11,len); - SSVAL(ptr,smb_vwv12,70 + strlen(mailslot)); - SSVAL(ptr,smb_vwv13,3); - SSVAL(ptr,smb_vwv14,1); - SSVAL(ptr,smb_vwv15,1); - SSVAL(ptr,smb_vwv16,2); - p2 = smb_buf(ptr); - strcpy(p2,mailslot); - p2 = skip_string(p2,1); - - memcpy(p2,buf,len); - p2 += len; - - dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */ - - p.ip = dest_ip; - p.port = DGRAM_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = DGRAM_PACKET; - - return(send_packet(&p)); -} + if (n <= 1) return; + putip(sort_ip, (char *)&ip); + qsort(data, n, 6, QSORT_CAST name_query_comp); +} diff --git a/source/libsmb/nterr.c b/source/libsmb/nterr.c new file mode 100644 index 00000000000..d2f9335000d --- /dev/null +++ b/source/libsmb/nterr.c @@ -0,0 +1,543 @@ +/* NT error codes. please read nterr.h */ + +#include "includes.h" +#include "nterr.h" + +typedef struct +{ + char *nt_errstr; + uint32 nt_errcode; + +} nt_err_code_struct; + +nt_err_code_struct nt_errs[] = +{ + { "NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL }, + { "NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED }, + { "NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS }, + { "NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH }, + { "NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION }, + { "STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW }, + { "NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR }, + { "NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA }, + { "NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE }, + { "NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK }, + { "NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC }, + { "NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID }, + { "NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED }, + { "NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER }, + { "NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE }, + { "NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE }, + { "NT_STATUS_INVALID_DEVICE_REQUEST", NT_STATUS_INVALID_DEVICE_REQUEST }, + { "NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE }, + { "NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME }, + { "NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE }, + { "NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA }, + { "NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR }, + { "NT_STATUS_MORE_PROCESSING_REQUIRED", NT_STATUS_MORE_PROCESSING_REQUIRED }, + { "NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY }, + { "NT_STATUS_CONFLICTING_ADDRESSES", NT_STATUS_CONFLICTING_ADDRESSES }, + { "NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW }, + { "NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM }, + { "NT_STATUS_UNABLE_TO_DELETE_SECTION", NT_STATUS_UNABLE_TO_DELETE_SECTION }, + { "NT_STATUS_INVALID_SYSTEM_SERVICE", NT_STATUS_INVALID_SYSTEM_SERVICE }, + { "NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION }, + { "NT_STATUS_INVALID_LOCK_SEQUENCE", NT_STATUS_INVALID_LOCK_SEQUENCE }, + { "NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE }, + { "NT_STATUS_INVALID_FILE_FOR_SECTION", NT_STATUS_INVALID_FILE_FOR_SECTION }, + { "NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED }, + { "NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED }, + { "NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL }, + { "NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH }, + { "NT_STATUS_NONCONTINUABLE_EXCEPTION", NT_STATUS_NONCONTINUABLE_EXCEPTION }, + { "NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION }, + { "NT_STATUS_UNWIND", NT_STATUS_UNWIND }, + { "NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK }, + { "NT_STATUS_INVALID_UNWIND_TARGET", NT_STATUS_INVALID_UNWIND_TARGET }, + { "NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED }, + { "NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR }, + { "NT_STATUS_UNABLE_TO_DECOMMIT_VM", NT_STATUS_UNABLE_TO_DECOMMIT_VM }, + { "NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED }, + { "NT_STATUS_INVALID_PORT_ATTRIBUTES", NT_STATUS_INVALID_PORT_ATTRIBUTES }, + { "NT_STATUS_PORT_MESSAGE_TOO_LONG", NT_STATUS_PORT_MESSAGE_TOO_LONG }, + { "NT_STATUS_INVALID_PARAMETER_MIX", NT_STATUS_INVALID_PARAMETER_MIX }, + { "NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER }, + { "NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR }, + { "NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID }, + { "NT_STATUS_OBJECT_NAME_NOT_FOUND", NT_STATUS_OBJECT_NAME_NOT_FOUND }, + { "NT_STATUS_OBJECT_NAME_COLLISION", NT_STATUS_OBJECT_NAME_COLLISION }, + { "NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE }, + { "NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED }, + { "NT_STATUS_DEVICE_ALREADY_ATTACHED", NT_STATUS_DEVICE_ALREADY_ATTACHED }, + { "NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID }, + { "NT_STATUS_OBJECT_PATH_NOT_FOUND", NT_STATUS_OBJECT_PATH_NOT_FOUND }, + { "NT_STATUS_OBJECT_PATH_SYNTAX_BAD", NT_STATUS_OBJECT_PATH_SYNTAX_BAD }, + { "NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN }, + { "NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR }, + { "NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR }, + { "NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR }, + { "NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG }, + { "NT_STATUS_PORT_CONNECTION_REFUSED", NT_STATUS_PORT_CONNECTION_REFUSED }, + { "NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE }, + { "NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION }, + { "NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED }, + { "NT_STATUS_INVALID_PAGE_PROTECTION", NT_STATUS_INVALID_PAGE_PROTECTION }, + { "NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED }, + { "NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED }, + { "NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET }, + { "NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE }, + { "NT_STATUS_SUSPEND_COUNT_EXCEEDED", NT_STATUS_SUSPEND_COUNT_EXCEEDED }, + { "NT_STATUS_THREAD_IS_TERMINATING", NT_STATUS_THREAD_IS_TERMINATING }, + { "NT_STATUS_BAD_WORKING_SET_LIMIT", NT_STATUS_BAD_WORKING_SET_LIMIT }, + { "NT_STATUS_INCOMPATIBLE_FILE_MAP", NT_STATUS_INCOMPATIBLE_FILE_MAP }, + { "NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION }, + { "NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED }, + { "NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE }, + { "NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY }, + { "NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE }, + { "NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR }, + { "NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT }, + { "NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED }, + { "NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING }, + { "NT_STATUS_CTL_FILE_NOT_SUPPORTED", NT_STATUS_CTL_FILE_NOT_SUPPORTED }, + { "NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION }, + { "NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH }, + { "NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER }, + { "NT_STATUS_INVALID_PRIMARY_GROUP", NT_STATUS_INVALID_PRIMARY_GROUP }, + { "NT_STATUS_NO_IMPERSONATION_TOKEN", NT_STATUS_NO_IMPERSONATION_TOKEN }, + { "NT_STATUS_CANT_DISABLE_MANDATORY", NT_STATUS_CANT_DISABLE_MANDATORY }, + { "NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS }, + { "NT_STATUS_NO_SUCH_LOGON_SESSION", NT_STATUS_NO_SUCH_LOGON_SESSION }, + { "NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE }, + { "NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD }, + { "NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME }, + { "NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS }, + { "NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER }, + { "NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS }, + { "NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP }, + { "NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP }, + { "NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP }, + { "NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN }, + { "NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD }, + { "NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD }, + { "NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION }, + { "NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE }, + { "NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION }, + { "NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS }, + { "NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION }, + { "NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED }, + { "NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED }, + { "NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED }, + { "NT_STATUS_TOO_MANY_LUIDS_REQUESTED", NT_STATUS_TOO_MANY_LUIDS_REQUESTED }, + { "NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED }, + { "NT_STATUS_INVALID_SUB_AUTHORITY", NT_STATUS_INVALID_SUB_AUTHORITY }, + { "NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL }, + { "NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID }, + { "NT_STATUS_INVALID_SECURITY_DESCR", NT_STATUS_INVALID_SECURITY_DESCR }, + { "NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND }, + { "NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT }, + { "NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN }, + { "NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL }, + { "NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED }, + { "NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL }, + { "NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED }, + { "NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED }, + { "NT_STATUS_TOO_MANY_GUIDS_REQUESTED", NT_STATUS_TOO_MANY_GUIDS_REQUESTED }, + { "NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED }, + { "NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY }, + { "NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED }, + { "NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL }, + { "NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED }, + { "NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA }, + { "NT_STATUS_RESOURCE_DATA_NOT_FOUND", NT_STATUS_RESOURCE_DATA_NOT_FOUND }, + { "NT_STATUS_RESOURCE_TYPE_NOT_FOUND", NT_STATUS_RESOURCE_TYPE_NOT_FOUND }, + { "NT_STATUS_RESOURCE_NAME_NOT_FOUND", NT_STATUS_RESOURCE_NAME_NOT_FOUND }, + { "NT_STATUS_ARRAY_BOUNDS_EXCEEDED", NT_STATUS_ARRAY_BOUNDS_EXCEEDED }, + { "NT_STATUS_FLOAT_DENORMAL_OPERAND", NT_STATUS_FLOAT_DENORMAL_OPERAND }, + { "NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO }, + { "NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT }, + { "NT_STATUS_FLOAT_INVALID_OPERATION", NT_STATUS_FLOAT_INVALID_OPERATION }, + { "NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW }, + { "NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK }, + { "NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW }, + { "NT_STATUS_INTEGER_DIVIDE_BY_ZERO", NT_STATUS_INTEGER_DIVIDE_BY_ZERO }, + { "NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW }, + { "NT_STATUS_PRIVILEGED_INSTRUCTION", NT_STATUS_PRIVILEGED_INSTRUCTION }, + { "NT_STATUS_TOO_MANY_PAGING_FILES", NT_STATUS_TOO_MANY_PAGING_FILES }, + { "NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID }, + { "NT_STATUS_ALLOTTED_SPACE_EXCEEDED", NT_STATUS_ALLOTTED_SPACE_EXCEEDED }, + { "NT_STATUS_INSUFFICIENT_RESOURCES", NT_STATUS_INSUFFICIENT_RESOURCES }, + { "NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND }, + { "NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR }, + { "NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED }, + { "NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE }, + { "NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE }, + { "NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED }, + { "NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA }, + { "NT_STATUS_MEDIA_WRITE_PROTECTED", NT_STATUS_MEDIA_WRITE_PROTECTED }, + { "NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY }, + { "NT_STATUS_INVALID_GROUP_ATTRIBUTES", NT_STATUS_INVALID_GROUP_ATTRIBUTES }, + { "NT_STATUS_BAD_IMPERSONATION_LEVEL", NT_STATUS_BAD_IMPERSONATION_LEVEL }, + { "NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS }, + { "NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS }, + { "NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE }, + { "NT_STATUS_BAD_MASTER_BOOT_RECORD", NT_STATUS_BAD_MASTER_BOOT_RECORD }, + { "NT_STATUS_INSTRUCTION_MISALIGNMENT", NT_STATUS_INSTRUCTION_MISALIGNMENT }, + { "NT_STATUS_INSTANCE_NOT_AVAILABLE", NT_STATUS_INSTANCE_NOT_AVAILABLE }, + { "NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE }, + { "NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE }, + { "NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY }, + { "NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION }, + { "NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED }, + { "NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING }, + { "NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED }, + { "NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING }, + { "NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE }, + { "NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT }, + { "NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED }, + { "NT_STATUS_PROFILING_NOT_STARTED", NT_STATUS_PROFILING_NOT_STARTED }, + { "NT_STATUS_PROFILING_NOT_STOPPED", NT_STATUS_PROFILING_NOT_STOPPED }, + { "NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET }, + { "NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY }, + { "NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED }, + { "NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING }, + { "NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME }, + { "NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH }, + { "NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY }, + { "NT_STATUS_DEVICE_DOES_NOT_EXIST", NT_STATUS_DEVICE_DOES_NOT_EXIST }, + { "NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS }, + { "NT_STATUS_ADAPTER_HARDWARE_ERROR", NT_STATUS_ADAPTER_HARDWARE_ERROR }, + { "NT_STATUS_INVALID_NETWORK_RESPONSE", NT_STATUS_INVALID_NETWORK_RESPONSE }, + { "NT_STATUS_UNEXPECTED_NETWORK_ERROR", NT_STATUS_UNEXPECTED_NETWORK_ERROR }, + { "NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER }, + { "NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL }, + { "NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE }, + { "NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED }, + { "NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED }, + { "NT_STATUS_NETWORK_ACCESS_DENIED", NT_STATUS_NETWORK_ACCESS_DENIED }, + { "NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE }, + { "NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME }, + { "NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES }, + { "NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS }, + { "NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED }, + { "NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED }, + { "NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED }, + { "NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT }, + { "NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT }, + { "NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE }, + { "NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED }, + { "NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", NT_STATUS_VIRTUAL_CIRCUIT_CLOSED }, + { "NT_STATUS_NO_SECURITY_ON_OBJECT", NT_STATUS_NO_SECURITY_ON_OBJECT }, + { "NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT }, + { "NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY }, + { "NT_STATUS_CANT_ACCESS_DOMAIN_INFO", NT_STATUS_CANT_ACCESS_DOMAIN_INFO }, + { "NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF }, + { "NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE }, + { "NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE }, + { "NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE }, + { "NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN }, + { "NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS }, + { "NT_STATUS_DOMAIN_LIMIT_EXCEEDED", NT_STATUS_DOMAIN_LIMIT_EXCEEDED }, + { "NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED }, + { "NT_STATUS_INVALID_OPLOCK_PROTOCOL", NT_STATUS_INVALID_OPLOCK_PROTOCOL }, + { "NT_STATUS_INTERNAL_DB_CORRUPTION", NT_STATUS_INTERNAL_DB_CORRUPTION }, + { "NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR }, + { "NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED }, + { "NT_STATUS_BAD_DESCRIPTOR_FORMAT", NT_STATUS_BAD_DESCRIPTOR_FORMAT }, + { "NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER }, + { "NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR }, + { "NT_STATUS_UNEXPECTED_MM_CREATE_ERR", NT_STATUS_UNEXPECTED_MM_CREATE_ERR }, + { "NT_STATUS_UNEXPECTED_MM_MAP_ERROR", NT_STATUS_UNEXPECTED_MM_MAP_ERROR }, + { "NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", NT_STATUS_UNEXPECTED_MM_EXTEND_ERR }, + { "NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS }, + { "NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS }, + { "NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1 }, + { "NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2 }, + { "NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3 }, + { "NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4 }, + { "NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5 }, + { "NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6 }, + { "NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7 }, + { "NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8 }, + { "NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9 }, + { "NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10 }, + { "NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11 }, + { "NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12 }, + { "NT_STATUS_REDIRECTOR_NOT_STARTED", NT_STATUS_REDIRECTOR_NOT_STARTED }, + { "NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED }, + { "NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW }, + { "NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE }, + { "NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE }, + { "NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY }, + { "NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR }, + { "NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY }, + { "NT_STATUS_BAD_LOGON_SESSION_STATE", NT_STATUS_BAD_LOGON_SESSION_STATE }, + { "NT_STATUS_LOGON_SESSION_COLLISION", NT_STATUS_LOGON_SESSION_COLLISION }, + { "NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG }, + { "NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN }, + { "NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE }, + { "NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND }, + { "NT_STATUS_PROCESS_IS_TERMINATING", NT_STATUS_PROCESS_IS_TERMINATING }, + { "NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE }, + { "NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION }, + { "NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE }, + { "NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED }, + { "NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT }, + { "NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST }, + { "NT_STATUS_ABIOS_LID_ALREADY_OWNED", NT_STATUS_ABIOS_LID_ALREADY_OWNED }, + { "NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER }, + { "NT_STATUS_ABIOS_INVALID_COMMAND", NT_STATUS_ABIOS_INVALID_COMMAND }, + { "NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID }, + { "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE }, + { "NT_STATUS_ABIOS_INVALID_SELECTOR", NT_STATUS_ABIOS_INVALID_SELECTOR }, + { "NT_STATUS_NO_LDT", NT_STATUS_NO_LDT }, + { "NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE }, + { "NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET }, + { "NT_STATUS_INVALID_LDT_DESCRIPTOR", NT_STATUS_INVALID_LDT_DESCRIPTOR }, + { "NT_STATUS_INVALID_IMAGE_NE_FORMAT", NT_STATUS_INVALID_IMAGE_NE_FORMAT }, + { "NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE }, + { "NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE }, + { "NT_STATUS_MAPPED_FILE_SIZE_ZERO", NT_STATUS_MAPPED_FILE_SIZE_ZERO }, + { "NT_STATUS_TOO_MANY_OPENED_FILES", NT_STATUS_TOO_MANY_OPENED_FILES }, + { "NT_STATUS_CANCELLED", NT_STATUS_CANCELLED }, + { "NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE }, + { "NT_STATUS_INVALID_COMPUTER_NAME", NT_STATUS_INVALID_COMPUTER_NAME }, + { "NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED }, + { "NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT }, + { "NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP }, + { "NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER }, + { "NT_STATUS_MEMBERS_PRIMARY_GROUP", NT_STATUS_MEMBERS_PRIMARY_GROUP }, + { "NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED }, + { "NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS }, + { "NT_STATUS_THREAD_NOT_IN_PROCESS", NT_STATUS_THREAD_NOT_IN_PROCESS }, + { "NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE }, + { "NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", NT_STATUS_PAGEFILE_QUOTA_EXCEEDED }, + { "NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT }, + { "NT_STATUS_INVALID_IMAGE_LE_FORMAT", NT_STATUS_INVALID_IMAGE_LE_FORMAT }, + { "NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ }, + { "NT_STATUS_INVALID_IMAGE_PROTECT", NT_STATUS_INVALID_IMAGE_PROTECT }, + { "NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16 }, + { "NT_STATUS_LOGON_SERVER_CONFLICT", NT_STATUS_LOGON_SERVER_CONFLICT }, + { "NT_STATUS_TIME_DIFFERENCE_AT_DC", NT_STATUS_TIME_DIFFERENCE_AT_DC }, + { "NT_STATUS_SYNCHRONIZATION_REQUIRED", NT_STATUS_SYNCHRONIZATION_REQUIRED }, + { "NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND }, + { "NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED }, + { "NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED }, + { "NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND }, + { "NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND }, + { "NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT }, + { "NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT }, + { "NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT }, + { "NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES }, + { "NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED }, + { "NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT }, + { "NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION }, + { "NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS }, + { "NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED }, + { "NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE }, + { "NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION }, + { "NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE }, + { "NT_STATUS_PAGEFILE_CREATE_FAILED", NT_STATUS_PAGEFILE_CREATE_FAILED }, + { "NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE }, + { "NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL }, + { "NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE }, + { "NT_STATUS_ILLEGAL_FLOAT_CONTEXT", NT_STATUS_ILLEGAL_FLOAT_CONTEXT }, + { "NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN }, + { "NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT }, + { "NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED }, + { "NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR }, + { "NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME }, + { "NT_STATUS_SERIAL_NO_DEVICE_INITED", NT_STATUS_SERIAL_NO_DEVICE_INITED }, + { "NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS }, + { "NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS }, + { "NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS }, + { "NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS }, + { "NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED }, + { "NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS }, + { "NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG }, + { "NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR }, + { "NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE }, + { "NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS }, + { "NT_STATUS_LOGON_TYPE_NOT_GRANTED", NT_STATUS_LOGON_TYPE_NOT_GRANTED }, + { "NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE }, + { "NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED }, + { "NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR }, + { "NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER }, + { "NT_STATUS_ILL_FORMED_SERVICE_ENTRY", NT_STATUS_ILL_FORMED_SERVICE_ENTRY }, + { "NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER }, + { "NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER }, + { "NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER }, + { "NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME }, + { "NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND }, + { "NT_STATUS_FLOPPY_WRONG_CYLINDER", NT_STATUS_FLOPPY_WRONG_CYLINDER }, + { "NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR }, + { "NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS }, + { "NT_STATUS_DISK_RECALIBRATE_FAILED", NT_STATUS_DISK_RECALIBRATE_FAILED }, + { "NT_STATUS_DISK_OPERATION_FAILED", NT_STATUS_DISK_OPERATION_FAILED }, + { "NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED }, + { "NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY }, + { "NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING }, + { "NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE }, + { "NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH }, + { "NT_STATUS_DEVICE_NOT_PARTITIONED", NT_STATUS_DEVICE_NOT_PARTITIONED }, + { "NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA }, + { "NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", NT_STATUS_UNABLE_TO_UNLOAD_MEDIA }, + { "NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW }, + { "NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA }, + { "NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER }, + { "NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER }, + { "NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED }, + { "NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE }, + { "NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS }, + { "NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED }, + { "NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN }, + { "NT_STATUS_CHILD_MUST_BE_VOLATILE", NT_STATUS_CHILD_MUST_BE_VOLATILE }, + { "NT_STATUS_DEVICE_CONFIGURATION_ERROR", NT_STATUS_DEVICE_CONFIGURATION_ERROR }, + { "NT_STATUS_DRIVER_INTERNAL_ERROR", NT_STATUS_DRIVER_INTERNAL_ERROR }, + { "NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE }, + { "NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR }, + { "NT_STATUS_DEVICE_PROTOCOL_ERROR", NT_STATUS_DEVICE_PROTOCOL_ERROR }, + { "NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER }, + { "NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL }, + { "NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE }, + { "NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET }, + { "NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT }, + { "NT_STATUS_TRUSTED_DOMAIN_FAILURE", NT_STATUS_TRUSTED_DOMAIN_FAILURE }, + { "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE }, + { "NT_STATUS_EVENTLOG_FILE_CORRUPT", NT_STATUS_EVENTLOG_FILE_CORRUPT }, + { "NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START }, + { "NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE }, + { "NT_STATUS_MUTANT_LIMIT_EXCEEDED", NT_STATUS_MUTANT_LIMIT_EXCEEDED }, + { "NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED }, + { "NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED }, + { "NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK }, + { "NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", NT_STATUS_NETWORK_CREDENTIAL_CONFLICT }, + { "NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT }, + { "NT_STATUS_EVENTLOG_FILE_CHANGED", NT_STATUS_EVENTLOG_FILE_CHANGED }, + { "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT }, + { "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT }, + { "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT }, + { "NT_STATUS_DOMAIN_TRUST_INCONSISTENT", NT_STATUS_DOMAIN_TRUST_INCONSISTENT }, + { "NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED }, + { "NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY }, + { "NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED }, + { "NT_STATUS_RESOURCE_LANG_NOT_FOUND", NT_STATUS_RESOURCE_LANG_NOT_FOUND }, + { "NT_STATUS_INSUFF_SERVER_RESOURCES", NT_STATUS_INSUFF_SERVER_RESOURCES }, + { "NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE }, + { "NT_STATUS_INVALID_ADDRESS_COMPONENT", NT_STATUS_INVALID_ADDRESS_COMPONENT }, + { "NT_STATUS_INVALID_ADDRESS_WILDCARD", NT_STATUS_INVALID_ADDRESS_WILDCARD }, + { "NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES }, + { "NT_STATUS_ADDRESS_ALREADY_EXISTS", NT_STATUS_ADDRESS_ALREADY_EXISTS }, + { "NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED }, + { "NT_STATUS_CONNECTION_DISCONNECTED", NT_STATUS_CONNECTION_DISCONNECTED }, + { "NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET }, + { "NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES }, + { "NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED }, + { "NT_STATUS_TRANSACTION_TIMED_OUT", NT_STATUS_TRANSACTION_TIMED_OUT }, + { "NT_STATUS_TRANSACTION_NO_RELEASE", NT_STATUS_TRANSACTION_NO_RELEASE }, + { "NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH }, + { "NT_STATUS_TRANSACTION_RESPONDED", NT_STATUS_TRANSACTION_RESPONDED }, + { "NT_STATUS_TRANSACTION_INVALID_ID", NT_STATUS_TRANSACTION_INVALID_ID }, + { "NT_STATUS_TRANSACTION_INVALID_TYPE", NT_STATUS_TRANSACTION_INVALID_TYPE }, + { "NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION }, + { "NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION }, + { "NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", NT_STATUS_CANNOT_LOAD_REGISTRY_FILE }, + { "NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED }, + { "NT_STATUS_SYSTEM_PROCESS_TERMINATED", NT_STATUS_SYSTEM_PROCESS_TERMINATED }, + { "NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED }, + { "NT_STATUS_NO_BROWSER_SERVERS_FOUND", NT_STATUS_NO_BROWSER_SERVERS_FOUND }, + { "NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR }, + { "NT_STATUS_DRIVER_CANCEL_TIMEOUT", NT_STATUS_DRIVER_CANCEL_TIMEOUT }, + { "NT_STATUS_REPLY_MESSAGE_MISMATCH", NT_STATUS_REPLY_MESSAGE_MISMATCH }, + { "NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT }, + { "NT_STATUS_IMAGE_CHECKSUM_MISMATCH", NT_STATUS_IMAGE_CHECKSUM_MISMATCH }, + { "NT_STATUS_LOST_WRITEBEHIND_DATA", NT_STATUS_LOST_WRITEBEHIND_DATA }, + { "NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID }, + { "NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE }, + { "NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND }, + { "NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM }, + { "NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE }, + { "NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ }, + { "NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK }, + { "NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID }, + { "NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS }, + { "NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE }, + { "NT_STATUS_RETRY", NT_STATUS_RETRY }, + { "NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE }, + { "NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET }, + { "NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND }, + { "NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW }, + { "NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT }, + { "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND }, + { "NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT }, + { "NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE }, + { "NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED }, + { "NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT }, + { "NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", NT_STATUS_ADDRESS_ALREADY_ASSOCIATED }, + { "NT_STATUS_ADDRESS_NOT_ASSOCIATED", NT_STATUS_ADDRESS_NOT_ASSOCIATED }, + { "NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID }, + { "NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE }, + { "NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE }, + { "NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE }, + { "NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE }, + { "NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE }, + { "NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED }, + { "NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED }, + { "NT_STATUS_BAD_COMPRESSION_BUFFER", NT_STATUS_BAD_COMPRESSION_BUFFER }, + { "NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE }, + { "NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED }, + { "NT_STATUS_TIMER_RESOLUTION_NOT_SET", NT_STATUS_TIMER_RESOLUTION_NOT_SET }, + { "NT_STATUS_CONNECTION_COUNT_LIMIT", NT_STATUS_CONNECTION_COUNT_LIMIT }, + { "NT_STATUS_LOGIN_TIME_RESTRICTION", NT_STATUS_LOGIN_TIME_RESTRICTION }, + { "NT_STATUS_LOGIN_WKSTA_RESTRICTION", NT_STATUS_LOGIN_WKSTA_RESTRICTION }, + { "NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH }, + { "NT_STATUS_INSUFFICIENT_LOGON_INFO", NT_STATUS_INSUFFICIENT_LOGON_INFO }, + { "NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT }, + { "NT_STATUS_BAD_SERVICE_ENTRYPOINT", NT_STATUS_BAD_SERVICE_ENTRYPOINT }, + { "NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST }, + { "NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1 }, + { "NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2 }, + { "NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT }, + { "NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED }, + { "NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE }, + { "NT_STATUS_LICENSE_QUOTA_EXCEEDED", NT_STATUS_LICENSE_QUOTA_EXCEEDED }, + { "NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT }, + { "NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT }, + { "NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT }, + { "NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE }, + { "NT_STATUS_UNSUPPORTED_COMPRESSION", NT_STATUS_UNSUPPORTED_COMPRESSION }, + { "NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE }, + { "NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH }, + { "NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", NT_STATUS_DRIVER_ORDINAL_NOT_FOUND }, + { "NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND }, + { "NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED }, + { "NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS }, + { "NT_STATUS_QUOTA_LIST_INCONSISTENT", NT_STATUS_QUOTA_LIST_INCONSISTENT }, + { "NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE }, + { NULL, 0 } +}; + +/***************************************************************************** + returns an NT error message. not amazingly helpful, but better than a number. + *****************************************************************************/ +char *get_nt_error_msg(uint32 nt_code) +{ + static pstring msg; + int idx = 0; + + pstrcpy(msg, "Unknown NT error"); + + nt_code &= 0xFFFF; + + while (nt_errs[idx].nt_errstr != NULL) + { + if (nt_errs[idx].nt_errcode == nt_code) + { + pstrcpy(msg, nt_errs[idx].nt_errstr); + return msg; + } + idx++; + } + return msg; +} + diff --git a/source/libsmb/pwd_cache.c b/source/libsmb/pwd_cache.c new file mode 100644 index 00000000000..92eee015b39 --- /dev/null +++ b/source/libsmb/pwd_cache.c @@ -0,0 +1,235 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Password cacheing. obfuscation is planned + Copyright (C) Luke Kenneth Casson Leighton 1996-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; + + +/**************************************************************************** +initialises a password structure +****************************************************************************/ +void pwd_init(struct pwd_info *pwd) +{ + bzero(pwd->password , sizeof(pwd->password )); + bzero(pwd->smb_lm_pwd, sizeof(pwd->smb_lm_pwd)); + bzero(pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd)); + bzero(pwd->smb_lm_owf, sizeof(pwd->smb_lm_owf)); + bzero(pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf)); + + pwd->null_pwd = True; /* safest option... */ + pwd->cleartext = False; + pwd->crypted = False; +} + +/**************************************************************************** +de-obfuscates a password +****************************************************************************/ +static void pwd_deobfuscate(struct pwd_info *pwd) +{ +} + +/**************************************************************************** +obfuscates a password +****************************************************************************/ +static void pwd_obfuscate(struct pwd_info *pwd) +{ +} + +/**************************************************************************** +sets the obfuscation key info +****************************************************************************/ +void pwd_obfuscate_key(struct pwd_info *pwd, uint32 int_key, char *str_key) +{ +} + +/**************************************************************************** +reads a password +****************************************************************************/ +void pwd_read(struct pwd_info *pwd, char *passwd_report, BOOL do_encrypt) +{ + /* grab a password */ + char *user_pass; + + pwd_init(pwd); + + user_pass = (char*)getpass(passwd_report); + + if (user_pass == NULL || user_pass[0] == 0) + { + pwd_set_nullpwd(pwd); + } + else if (do_encrypt) + { + pwd_make_lm_nt_16(pwd, user_pass); + } + else + { + pwd_set_cleartext(pwd, user_pass); + } +} + +/**************************************************************************** + stores a cleartext password + ****************************************************************************/ +void pwd_set_nullpwd(struct pwd_info *pwd) +{ + pwd_init(pwd); + + pwd->cleartext = False; + pwd->null_pwd = True; + pwd->crypted = False; +} + +/**************************************************************************** + stores a cleartext password + ****************************************************************************/ +void pwd_set_cleartext(struct pwd_info *pwd, char *clr) +{ + pwd_init(pwd); + fstrcpy(pwd->password, clr); + pwd->cleartext = True; + pwd->null_pwd = False; + pwd->crypted = False; + + pwd_obfuscate(pwd); +} + +/**************************************************************************** + gets a cleartext password + ****************************************************************************/ +void pwd_get_cleartext(struct pwd_info *pwd, char *clr) +{ + pwd_deobfuscate(pwd); + if (pwd->cleartext) + { + fstrcpy(clr, pwd->password); + } + else + { + clr[0] = 0; + } + pwd_obfuscate(pwd); +} + +/**************************************************************************** + stores lm and nt hashed passwords + ****************************************************************************/ +void pwd_set_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16]) +{ + pwd_init(pwd); + + if (lm_pwd) + { + memcpy(pwd->smb_lm_pwd, lm_pwd, 16); + } + else + { + bzero(pwd->smb_lm_pwd, 16); + } + + if (nt_pwd) + { + memcpy(pwd->smb_nt_pwd, nt_pwd, 16); + } + else + { + bzero(pwd->smb_nt_pwd, 16); + } + + pwd->null_pwd = False; + pwd->cleartext = False; + pwd->crypted = False; + + pwd_obfuscate(pwd); +} + +/**************************************************************************** + gets lm and nt hashed passwords + ****************************************************************************/ +void pwd_get_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16]) +{ + pwd_deobfuscate(pwd); + memcpy(lm_pwd, pwd->smb_lm_pwd, 16); + memcpy(nt_pwd, pwd->smb_nt_pwd, 16); + pwd_obfuscate(pwd); +} + +/**************************************************************************** + makes lm and nt hashed passwords + ****************************************************************************/ +void pwd_make_lm_nt_16(struct pwd_info *pwd, char *clr) +{ + pwd_init(pwd); + + nt_lm_owf_gen(clr, pwd->smb_nt_pwd, pwd->smb_lm_pwd); + pwd->null_pwd = False; + pwd->cleartext = False; + pwd->crypted = False; + + pwd_obfuscate(pwd); +} + +/**************************************************************************** + makes lm and nt OWF crypts + ****************************************************************************/ +void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8]) +{ + pwd_deobfuscate(pwd); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("client cryptkey: ")); + dump_data(100, cryptkey, 8); +#endif + + SMBOWFencrypt(pwd->smb_nt_pwd, cryptkey, pwd->smb_nt_owf); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("nt_owf_passwd: ")); + dump_data(100, pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf)); + DEBUG(100,("nt_sess_pwd: ")); + dump_data(100, pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd)); +#endif + + SMBOWFencrypt(pwd->smb_lm_pwd, cryptkey, pwd->smb_lm_owf); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("lm_owf_passwd: ")); + dump_data(100, pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf)); + DEBUG(100,("lm_sess_pwd: ")); + dump_data(100, pwd->smb_lm_pwd, sizeof(pwd->smb_lm_pwd)); +#endif + + pwd->crypted = True; + + pwd_obfuscate(pwd); +} + +/**************************************************************************** + gets lm and nt crypts + ****************************************************************************/ +void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], uchar nt_owf[24]) +{ + pwd_deobfuscate(pwd); + memcpy(lm_owf, pwd->smb_lm_owf, 24); + memcpy(nt_owf, pwd->smb_nt_owf, 24); + pwd_obfuscate(pwd); +} diff --git a/source/libsmb/smbdes.c b/source/libsmb/smbdes.c new file mode 100644 index 00000000000..eebe0dc54fe --- /dev/null +++ b/source/libsmb/smbdes.c @@ -0,0 +1,399 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + + a partial implementation of DES designed for use in the + SMB authentication protocol + + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +/* NOTES: + + This code makes no attempt to be fast! In fact, it is a very + slow implementation + + This code is NOT a complete DES implementation. It implements only + the minimum necessary for SMB authentication, as used by all SMB + products (including every copy of Microsoft Windows95 ever sold) + + In particular, it can only do a unchained forward DES pass. This + means it is not possible to use this code for encryption/decryption + of data, instead it is only useful as a "hash" algorithm. + + There is no entry point into this code that allows normal DES operation. + + I believe this means that this code does not come under ITAR + regulations but this is NOT a legal opinion. If you are concerned + about the applicability of ITAR regulations to this code then you + should confirm it for yourself (and maybe let me know if you come + up with a different answer to the one above) +*/ + + +#define uchar unsigned char + +static uchar perm1[56] = {57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4}; + +static uchar perm2[48] = {14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32}; + +static uchar perm3[64] = {58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7}; + +static uchar perm4[48] = { 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1}; + +static uchar perm5[32] = { 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25}; + + +static uchar perm6[64] ={ 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25}; + + +static uchar sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}; + +static uchar sbox[8][4][16] = { + {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, + {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, + {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, + {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}}, + + {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, + {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, + {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, + {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}}, + + {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, + {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, + {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, + {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}}, + + {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, + {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, + {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, + {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}}, + + {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, + {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, + {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, + {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}}, + + {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, + {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, + {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, + {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}}, + + {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, + {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, + {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, + {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}}, + + {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, + {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, + {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, + {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}}; + +static void permute(char *out, char *in, uchar *p, int n) +{ + int i; + for (i=0;i<n;i++) + out[i] = in[p[i]-1]; +} + +static void lshift(char *d, int count, int n) +{ + char out[64]; + int i; + for (i=0;i<n;i++) + out[i] = d[(i+count)%n]; + for (i=0;i<n;i++) + d[i] = out[i]; +} + +static void concat(char *out, char *in1, char *in2, int l1, int l2) +{ + while (l1--) + *out++ = *in1++; + while (l2--) + *out++ = *in2++; +} + +static void xor(char *out, char *in1, char *in2, int n) +{ + int i; + for (i=0;i<n;i++) + out[i] = in1[i] ^ in2[i]; +} + +static void dohash(char *out, char *in, char *key, int forw) +{ + int i, j, k; + char pk1[56]; + char c[28]; + char d[28]; + char cd[56]; + char ki[16][48]; + char pd1[64]; + char l[32], r[32]; + char rl[64]; + + permute(pk1, key, perm1, 56); + + for (i=0;i<28;i++) + c[i] = pk1[i]; + for (i=0;i<28;i++) + d[i] = pk1[i+28]; + + for (i=0;i<16;i++) { + lshift(c, sc[i], 28); + lshift(d, sc[i], 28); + + concat(cd, c, d, 28, 28); + permute(ki[i], cd, perm2, 48); + } + + permute(pd1, in, perm3, 64); + + for (j=0;j<32;j++) { + l[j] = pd1[j]; + r[j] = pd1[j+32]; + } + + for (i=0;i<16;i++) { + char er[48]; + char erk[48]; + char b[8][6]; + char cb[32]; + char pcb[32]; + char r2[32]; + + permute(er, r, perm4, 48); + + xor(erk, er, ki[forw ? i : 15 - i], 48); + + for (j=0;j<8;j++) + for (k=0;k<6;k++) + b[j][k] = erk[j*6 + k]; + + for (j=0;j<8;j++) { + int m, n; + m = (b[j][0]<<1) | b[j][5]; + + n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4]; + + for (k=0;k<4;k++) + b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0; + } + + for (j=0;j<8;j++) + for (k=0;k<4;k++) + cb[j*4+k] = b[j][k]; + permute(pcb, cb, perm5, 32); + + xor(r2, l, pcb, 32); + + for (j=0;j<32;j++) + l[j] = r[j]; + + for (j=0;j<32;j++) + r[j] = r2[j]; + } + + concat(rl, r, l, 32, 32); + + permute(out, rl, perm6, 64); +} + +static void str_to_key(unsigned char *str,unsigned char *key) +{ + int i; + + key[0] = str[0]>>1; + key[1] = ((str[0]&0x01)<<6) | (str[1]>>2); + key[2] = ((str[1]&0x03)<<5) | (str[2]>>3); + key[3] = ((str[2]&0x07)<<4) | (str[3]>>4); + key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5); + key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6); + key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7); + key[7] = str[6]&0x7F; + for (i=0;i<8;i++) { + key[i] = (key[i]<<1); + } +} + + +static void smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw) +{ + int i; + char outb[64]; + char inb[64]; + char keyb[64]; + unsigned char key2[8]; + + str_to_key(key, key2); + + for (i=0;i<64;i++) { + inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0; + keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0; + outb[i] = 0; + } + + dohash(outb, inb, keyb, forw); + + for (i=0;i<8;i++) { + out[i] = 0; + } + + for (i=0;i<64;i++) { + if (outb[i]) + out[i/8] |= (1<<(7-(i%8))); + } +} + +void E_P16(unsigned char *p14,unsigned char *p16) +{ + unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; + smbhash(p16, sp8, p14, 1); + smbhash(p16+8, sp8, p14+7, 1); +} + +void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) +{ + smbhash(p24, c8, p21, 1); + smbhash(p24+8, c8, p21+7, 1); + smbhash(p24+16, c8, p21+14, 1); +} + +void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) +{ + smbhash(out, in, p14, 0); + smbhash(out+8, in+8, p14+7, 0); +} + +void E_old_pw_hash( unsigned char *p14, unsigned char *in, unsigned char *out) +{ + smbhash(out, in, p14, 1); + smbhash(out+8, in+8, p14+7, 1); +} + +void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key) +{ + unsigned char buf[8]; + + smbhash(buf, in, key, 1); + smbhash(out, buf, key+9, 1); +} + +void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key) +{ + unsigned char buf[8]; + static unsigned char key2[8]; + + smbhash(buf, in, key, 1); + key2[0] = key[7]; + smbhash(out, buf, key2, 1); +} + +void cred_hash3(unsigned char *out,unsigned char *in,unsigned char *key, int forw) +{ + static unsigned char key2[8]; + + smbhash(out, in, key, forw); + key2[0] = key[7]; + smbhash(out + 8, in + 8, key2, forw); +} + +void SamOEMhash( unsigned char *data, unsigned char *key, int val) +{ + unsigned char s_box[256]; + unsigned char index_i = 0; + unsigned char index_j = 0; + unsigned char j = 0; + int ind; + + for (ind = 0; ind < 256; ind++) + { + s_box[ind] = (unsigned char)ind; + } + + for( ind = 0; ind < 256; ind++) + { + unsigned char tc; + + j += (s_box[ind] + key[ind%16]); + + tc = s_box[ind]; + s_box[ind] = s_box[j]; + s_box[j] = tc; + } + + for( ind = 0; ind < (val ? 516 : 16); ind++) + { + unsigned char tc; + unsigned char t; + + index_i++; + index_j += s_box[index_i]; + + tc = s_box[index_i]; + s_box[index_i] = s_box[index_j]; + s_box[index_j] = tc; + + t = s_box[index_i] + s_box[index_j]; + data[ind] = data[ind] ^ s_box[t]; + } +} diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c index a0683b5d282..5a946e22c9d 100644 --- a/source/libsmb/smbencrypt.c +++ b/source/libsmb/smbencrypt.c @@ -1,9 +1,8 @@ -#ifdef SMB_PASSWD /* Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995. This program is free software; you can redistribute it and/or modify @@ -22,90 +21,11 @@ */ #include "includes.h" -#include "loadparm.h" -#include "des.h" -#include "md4.h" extern int DEBUGLEVEL; -#ifndef uchar -#define uchar unsigned char -#endif -#ifndef int16 -#define int16 unsigned short -#endif -#ifndef uint16 -#define uint16 unsigned short -#endif -#ifndef uint32 -#define uint32 unsigned int -#endif - #include "byteorder.h" -void str_to_key(uchar *str,uchar *key) -{ - void des_set_odd_parity(des_cblock *); - int i; - - key[0] = str[0]>>1; - key[1] = ((str[0]&0x01)<<6) | (str[1]>>2); - key[2] = ((str[1]&0x03)<<5) | (str[2]>>3); - key[3] = ((str[2]&0x07)<<4) | (str[3]>>4); - key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5); - key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6); - key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7); - key[7] = str[6]&0x7F; - for (i=0;i<8;i++) { - key[i] = (key[i]<<1); - } - des_set_odd_parity((des_cblock *)key); -} - -void D1(uchar *k, uchar *d, uchar *out) -{ - des_key_schedule ks; - des_cblock deskey; - - str_to_key(k,(uchar *)deskey); - des_set_key(deskey,ks); - des_ecb_encrypt(d, out, ks, DES_DECRYPT); -} - -void E1(uchar *k, uchar *d, uchar *out) -{ - des_key_schedule ks; - des_cblock deskey; - - str_to_key(k,(uchar *)deskey); - des_set_key(deskey,ks); - des_ecb_encrypt(d, out, ks, DES_ENCRYPT); -} - -void E_P16(uchar *p14,uchar *p16) -{ - uchar sp7[7]; - /* the following constant makes us compatible with other - implementations. Note that publishing this constant does not reduce the - security of the encryption mechanism */ - uchar sp8[] = {0xAA,0xD3,0xB4,0x35,0xB5,0x14,0x4,0xEE}; - uchar x[8]; - - memset(sp7,'\0',7); - - D1(sp7, sp8, x); - E1(p14, x, p16); - E1(p14+7, x, p16+8); -} - -void E_P24(uchar *p21, uchar *c8, uchar *p24) -{ - E1(p21, c8, p24); - E1(p21+7, c8, p24+8); - E1(p21+14, c8, p24+16); -} - - /* This implements the X/Open SMB password encryption It takes a password, a 8 byte "crypt key" and puts 24 bytes of @@ -161,30 +81,57 @@ static int _my_mbstowcs(int16 *dst, uchar *src, int len) void E_md4hash(uchar *passwd, uchar *p16) { - int i, len; + int len; int16 wpwd[129]; - MDstruct MD; - + /* Password cannot be longer than 128 characters */ - len = strlen(passwd); + len = strlen((char *)passwd); if(len > 128) len = 128; /* Password must be converted to NT unicode */ - _my_mbstowcs( wpwd, passwd, len); + _my_mbstowcs(wpwd, passwd, len); wpwd[len] = 0; /* Ensure string is null terminated */ /* Calculate length in bytes */ len = _my_wcslen(wpwd) * sizeof(int16); + + mdfour(p16, (unsigned char *)wpwd, len); +} + +/* Does both the NT and LM owfs of a user's password */ +void nt_lm_owf_gen(char *pwd, uchar nt_p16[16], uchar p16[16]) +{ + char passwd[130]; + StrnCpy(passwd, pwd, sizeof(passwd)-1); + + /* Calculate the MD4 hash (NT compatible) of the password */ + memset(nt_p16, '\0', 16); + E_md4hash((uchar *)passwd, nt_p16); + + /* Mangle the passwords into Lanman format */ + passwd[14] = '\0'; + strupper(passwd); + + /* Calculate the SMB (lanman) hash functions of the password */ + + memset(p16, '\0', 16); + E_P16((uchar *) passwd, (uchar *)p16); + + /* clear out local copy of user's password (just being paranoid). */ + bzero(passwd, sizeof(passwd)); +} + +/* Does the des encryption from the NT or LM MD4 hash. */ +void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]) +{ + uchar p21[21]; - MDbegin(&MD); - for(i = 0; i + 64 <= len; i += 64) - MDupdate(&MD,wpwd + (i/2), 512); - MDupdate(&MD,wpwd + (i/2),(len-i)*8); - SIVAL(p16,0,MD.buffer[0]); - SIVAL(p16,4,MD.buffer[1]); - SIVAL(p16,8,MD.buffer[2]); - SIVAL(p16,12,MD.buffer[3]); + memset(p21,'\0',21); + + memcpy(p21, passwd, 16); + E_P24(p21, c8, p24); } + /* Does the NT MD4 hash then des encryption. */ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24) @@ -197,6 +144,4 @@ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24) E_P24(p21, c8, p24); } -#else -void smbencrypt_dummy(void){} -#endif + diff --git a/source/libsmb/smberr.c b/source/libsmb/smberr.c new file mode 100644 index 00000000000..c2d8884d738 --- /dev/null +++ b/source/libsmb/smberr.c @@ -0,0 +1,181 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define NO_SYSLOG + +#include "includes.h" + +extern int DEBUGLEVEL; + +/* error code stuff - put together by Merik Karman + merik@blackadder.dsh.oz.au */ + +typedef struct +{ + char *name; + int code; + char *message; +} err_code_struct; + +/* Dos Error Messages */ +err_code_struct dos_msgs[] = { + {"ERRbadfunc",1,"Invalid function."}, + {"ERRbadfile",2,"File not found."}, + {"ERRbadpath",3,"Directory invalid."}, + {"ERRnofids",4,"No file descriptors available"}, + {"ERRnoaccess",5,"Access denied."}, + {"ERRbadfid",6,"Invalid file handle."}, + {"ERRbadmcb",7,"Memory control blocks destroyed."}, + {"ERRnomem",8,"Insufficient server memory to perform the requested function."}, + {"ERRbadmem",9,"Invalid memory block address."}, + {"ERRbadenv",10,"Invalid environment."}, + {"ERRbadformat",11,"Invalid format."}, + {"ERRbadaccess",12,"Invalid open mode."}, + {"ERRbaddata",13,"Invalid data."}, + {"ERR",14,"reserved."}, + {"ERRbaddrive",15,"Invalid drive specified."}, + {"ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."}, + {"ERRdiffdevice",17,"Not same device."}, + {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."}, + {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."}, + {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + {"ERRunsup", 50, "The operation is unsupported"}, + {"ERRnosuchshare", 67, "You specified an invalid share name"}, + {"ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."}, + {"ERRbadpipe",230,"Pipe invalid."}, + {"ERRpipebusy",231,"All instances of the requested pipe are busy."}, + {"ERRpipeclosing",232,"Pipe close in progress."}, + {"ERRnotconnected",233,"No process on other end of pipe."}, + {"ERRmoredata",234,"There is more data to be returned."}, + {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"}, + {NULL,-1,NULL}}; + +/* Server Error Messages */ +err_code_struct server_msgs[] = { + {"ERRerror",1,"Non-specific error code."}, + {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, + {"ERRbadtype",3,"reserved."}, + {"ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, + {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."}, + {"ERRinvnetname",6,"Invalid network name in tree connect."}, + {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, + {"ERRqfull",49,"Print queue full (files) -- returned by open print file."}, + {"ERRqtoobig",50,"Print queue full -- no space."}, + {"ERRqeof",51,"EOF on print queue dump."}, + {"ERRinvpfid",52,"Invalid print file FID."}, + {"ERRsmbcmd",64,"The server did not recognize the command received."}, + {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."}, + {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."}, + {"ERRreserved",68,"reserved."}, + {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, + {"ERRreserved",70,"reserved."}, + {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."}, + {"ERRpaused",81,"Server is paused."}, + {"ERRmsgoff",82,"Not receiving messages."}, + {"ERRnoroom",83,"No room to buffer message."}, + {"ERRrmuns",87,"Too many remote user names."}, + {"ERRtimeout",88,"Operation timed out."}, + {"ERRnoresource",89,"No resources currently available for request."}, + {"ERRtoomanyuids",90,"Too many UIDs active on this session."}, + {"ERRbaduid",91,"The UID is not known as a valid ID on this session."}, + {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."}, + {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."}, + {"ERRcontmpx",252,"Continue in MPX mode."}, + {"ERRreserved",253,"reserved."}, + {"ERRreserved",254,"reserved."}, + {"ERRnosupport",0xFFFF,"Function not supported."}, + {NULL,-1,NULL}}; + +/* Hard Error Messages */ +err_code_struct hard_msgs[] = { + {"ERRnowrite",19,"Attempt to write on write-protected diskette."}, + {"ERRbadunit",20,"Unknown unit."}, + {"ERRnotready",21,"Drive not ready."}, + {"ERRbadcmd",22,"Unknown command."}, + {"ERRdata",23,"Data error (CRC)."}, + {"ERRbadreq",24,"Bad request structure length."}, + {"ERRseek",25 ,"Seek error."}, + {"ERRbadmedia",26,"Unknown media type."}, + {"ERRbadsector",27,"Sector not found."}, + {"ERRnopaper",28,"Printer out of paper."}, + {"ERRwrite",29,"Write fault."}, + {"ERRread",30,"Read fault."}, + {"ERRgeneral",31,"General failure."}, + {"ERRbadshare",32,"An open conflicts with an existing open."}, + {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + {"ERRwrongdisk",34,"The wrong disk was found in a drive."}, + {"ERRFCBUnavail",35,"No FCBs are available to process request."}, + {"ERRsharebufexc",36,"A sharing buffer has been exceeded."}, + {NULL,-1,NULL}}; + + +struct +{ + int code; + char *class; + err_code_struct *err_msgs; +} err_classes[] = { + {0,"SUCCESS",NULL}, + {0x01,"ERRDOS",dos_msgs}, + {0x02,"ERRSRV",server_msgs}, + {0x03,"ERRHRD",hard_msgs}, + {0x04,"ERRXOS",NULL}, + {0xE1,"ERRRMX1",NULL}, + {0xE2,"ERRRMX2",NULL}, + {0xE3,"ERRRMX3",NULL}, + {0xFF,"ERRCMD",NULL}, + {-1,NULL,NULL}}; + + +/**************************************************************************** +return a SMB error string from a SMB buffer +****************************************************************************/ +char *smb_errstr(char *inbuf) +{ + static pstring ret; + int class = CVAL(inbuf,smb_rcls); + int num = SVAL(inbuf,smb_err); + int i,j; + + for (i=0;err_classes[i].class;i++) + if (err_classes[i].code == class) + { + if (err_classes[i].err_msgs) + { + err_code_struct *err = err_classes[i].err_msgs; + for (j=0;err[j].name;j++) + if (num == err[j].code) + { + if (DEBUGLEVEL > 0) + slprintf(ret, sizeof(ret) - 1, "%s - %s (%s)",err_classes[i].class, + err[j].name,err[j].message); + else + slprintf(ret, sizeof(ret) - 1, "%s - %s",err_classes[i].class,err[j].name); + return ret; + } + } + + slprintf(ret, sizeof(ret) - 1, "%s - %d",err_classes[i].class,num); + return ret; + } + + slprintf(ret, sizeof(ret) - 1, "Error: Unknown error (%d,%d)",class,num); + return(ret); +} |