1 /* UNIX SMBlib NetBIOS implementation
4 SMBlib Utility Routines
6 Copyright (C) Richard Sharpe 1996
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include "smblib-priv.h"
32 /* The following two arrays need to be in step! */
33 /* We must make it possible for callers to specify these ... */
35 const char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0",
36 "MICROSOFT NETWORKS 1.03",
37 "MICROSOFT NETWORKS 3.0",
49 int SMB_Types[] = {SMB_P_Core,
63 /* Figure out what protocol was accepted, given the list of dialect strings */
64 /* We offered, and the index back from the server. We allow for a user */
65 /* supplied list, and assume that it is a subset of our list */
67 int SMB_Figure_Protocol(const char *dialects[], int prot_index)
71 if (dialects == SMB_Prots) { /* The jobs is easy, just index into table */
73 return(SMB_Types[prot_index]);
75 else { /* Search through SMB_Prots looking for a match */
77 for (i = 0; SMB_Prots[i] != NULL; i++) {
79 if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) { /* A match */
87 /* If we got here, then we are in trouble, because the protocol was not */
88 /* One we understand ... */
90 return(SMB_P_Unknown);
97 /* Negotiate the protocol we will use from the list passed in Prots */
98 /* we return the index of the accepted protocol in NegProt, -1 indicates */
99 /* none acceptible, and our return value is 0 if ok, <0 if problems */
101 int SMB_Negotiate(SMB_Handle_Type Con_Handle, const char *Prots[])
103 struct RFCNB_Pkt *pkt;
104 int prots_len, i, pkt_len, prot, alloc_len;
107 /* Figure out how long the prot list will be and allocate space for it */
111 for (i = 0; Prots[i] != NULL; i++) {
113 prots_len = prots_len + strlen(Prots[i]) + 2; /* Account for null etc */
117 /* The -1 accounts for the one byte smb_buf we have because some systems */
118 /* don't like char msg_buf[] */
120 pkt_len = SMB_negp_len + prots_len;
122 /* Make sure that the pkt len is long enough for the max response ... */
123 /* Which is a problem, because the encryption key len eec may be long */
125 if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
127 alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
136 pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(alloc_len);
140 SMBlib_errno = SMBlibE_NoSpace;
145 /* Now plug in the bits we need */
147 memset(SMB_Hdr(pkt), 0, SMB_negp_len);
148 SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
149 *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot;
150 SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
151 SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
152 SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
153 SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
154 *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
156 SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
158 /* Now copy the prot strings in with the right stuff */
160 p = (char *)(SMB_Hdr(pkt) + SMB_negp_buf_offset);
162 for (i = 0; Prots[i] != NULL; i++) {
165 strcpy(p + 1, Prots[i]);
166 p = p + strlen(Prots[i]) + 2; /* Adjust len of p for null plus dialectID */
170 /* Now send the packet and sit back ... */
172 if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
176 fprintf(stderr, "Error sending negotiate protocol\n");
180 SMBlib_errno = -SMBlibE_SendFailed; /* Failed, check lower layer errno */
185 /* Now get the response ... */
187 if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, alloc_len) < 0) {
190 fprintf(stderr, "Error receiving response to negotiate\n");
194 SMBlib_errno = -SMBlibE_RecvFailed; /* Failed, check lower layer errno */
199 if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
202 fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n",
203 CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
204 SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
207 SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
209 SMBlib_errno = SMBlibE_Remote;
214 if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
217 fprintf(stderr, "None of our protocols was accepted ... ");
221 SMBlib_errno = SMBlibE_NegNoProt;
226 /* Now, unpack the info from the response, if any and evaluate the proto */
227 /* selected. We must make sure it is one we like ... */
229 Con_Handle -> prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
230 Con_Handle -> protocol = SMB_Figure_Protocol(Prots, prot);
232 if (Con_Handle -> protocol == SMB_P_Unknown) { /* No good ... */
235 SMBlib_errno = SMBlibE_ProtUnknown;
240 switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
242 case 0x01: /* No more info ... */
246 case 13: /* Up to and including LanMan 2.1 */
248 Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset);
249 Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00);
250 Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask;
252 Con_Handle -> max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset);
253 Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset);
254 Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset);
255 Con_Handle -> Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset);
256 Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset);
257 Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset);
258 Con_Handle -> Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset);
260 p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset);
261 fprintf(stderr, "%p", (char *)(SMB_Hdr(pkt) + SMB_negrLM_buf_offset));
262 memcpy(Con_Handle->Encrypt_Key, p, 8);
264 p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
266 strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
270 case 17: /* NT LM 0.12 and LN LM 1.0 */
272 Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset);
273 Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00);
274 Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask;
276 Con_Handle -> max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset);
277 Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset);
278 Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset);
279 Con_Handle -> MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset);
280 Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset);
281 Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset);
282 Con_Handle -> Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset);
284 p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset );
285 memcpy(Con_Handle -> Encrypt_Key, p, 8);
286 p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
288 strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
295 fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
296 fprintf(stderr, " wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
303 fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
311 /* Get our hostname */
313 void SMB_Get_My_Name(char *name, int len)
316 if (gethostname(name, len) < 0) { /* Error getting name */
318 strncpy(name, "unknown", len);
320 /* Should check the error */
323 fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
329 /* only keep the portion up to the first "." */