chiark / gitweb /
get sense of ferror check right
[inn-innduct.git] / authprogs / smbval / smblib-util.c
1 /* UNIX SMBlib NetBIOS implementation
2
3    Version 1.0
4    SMBlib Utility Routines
5
6    Copyright (C) Richard Sharpe 1996
7
8 */
9
10 /*
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.
15    
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.
20    
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.
24 */
25
26 #include "config.h"
27 #include "clibrary.h"
28
29 #include "smblib-priv.h"
30 #include "rfcnb.h"
31
32 /* The following two arrays need to be in step!              */
33 /* We must make it possible for callers to specify these ... */
34
35 const char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0", 
36                            "MICROSOFT NETWORKS 1.03",
37                            "MICROSOFT NETWORKS 3.0",
38                            "DOS LANMAN1.0",
39                            "LANMAN1.0",
40                            "DOS LM1.2X002",
41                            "LM1.2X002",
42                            "DOS LANMAN2.1",
43                            "LANMAN2.1",
44                            "Samba",
45                            "NT LM 0.12",
46                            "NT LANMAN 1.0",
47                            NULL};
48
49 int SMB_Types[] = {SMB_P_Core,
50                    SMB_P_CorePlus,
51                    SMB_P_DOSLanMan1,
52                    SMB_P_DOSLanMan1,
53                    SMB_P_LanMan1,
54                    SMB_P_DOSLanMan2,
55                    SMB_P_LanMan2,
56                    SMB_P_LanMan2_1,
57                    SMB_P_LanMan2_1,
58                    SMB_P_NT1,
59                    SMB_P_NT1,
60                    SMB_P_NT1,
61                    -1};
62
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                */
66
67 int SMB_Figure_Protocol(const char *dialects[], int prot_index)
68
69 { int i;
70
71   if (dialects == SMB_Prots) { /* The jobs is easy, just index into table */
72
73     return(SMB_Types[prot_index]);
74   }
75   else { /* Search through SMB_Prots looking for a match */
76
77     for (i = 0; SMB_Prots[i] != NULL; i++) {
78
79       if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) { /* A match */
80
81         return(SMB_Types[i]);
82
83       }
84
85     }
86
87     /* If we got here, then we are in trouble, because the protocol was not */
88     /* One we understand ...                                                */
89
90     return(SMB_P_Unknown);
91
92   }
93
94 }
95
96
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       */
100
101 int SMB_Negotiate(SMB_Handle_Type Con_Handle, const char *Prots[])
102 {
103   struct RFCNB_Pkt *pkt;
104   int prots_len, i, pkt_len, prot, alloc_len;
105   char *p;
106
107   /* Figure out how long the prot list will be and allocate space for it */
108
109   prots_len = 0;
110
111   for (i = 0; Prots[i] != NULL; i++) {
112
113     prots_len = prots_len + strlen(Prots[i]) + 2; /* Account for null etc */
114
115   }
116
117   /* The -1 accounts for the one byte smb_buf we have because some systems */
118   /* don't like char msg_buf[]                                             */
119
120   pkt_len = SMB_negp_len + prots_len;
121
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   */
124
125   if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
126
127     alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
128
129   }
130   else {
131
132     alloc_len = pkt_len;
133
134   }
135
136   pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(alloc_len);
137
138   if (pkt == NULL) {
139
140     SMBlib_errno = SMBlibE_NoSpace;
141     return(SMBlibE_BAD);
142
143   }
144
145   /* Now plug in the bits we need */
146
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;
155
156   SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
157
158   /* Now copy the prot strings in with the right stuff */
159
160   p = (char *)(SMB_Hdr(pkt) + SMB_negp_buf_offset);
161
162   for (i = 0; Prots[i] != NULL; i++) {
163
164     *p = SMBdialectID;
165     strcpy(p + 1, Prots[i]);
166     p = p + strlen(Prots[i]) + 2; /* Adjust len of p for null plus dialectID */
167
168   }
169
170   /* Now send the packet and sit back ... */
171
172   if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
173
174
175 #ifdef DEBUG
176     fprintf(stderr, "Error sending negotiate protocol\n");
177 #endif
178
179     RFCNB_Free_Pkt(pkt);
180     SMBlib_errno = -SMBlibE_SendFailed; /* Failed, check lower layer errno */
181     return(SMBlibE_BAD);
182
183   }
184
185   /* Now get the response ... */
186
187   if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, alloc_len) < 0) {
188
189 #ifdef DEBUG
190     fprintf(stderr, "Error receiving response to negotiate\n");
191 #endif
192
193     RFCNB_Free_Pkt(pkt);
194     SMBlib_errno = -SMBlibE_RecvFailed; /* Failed, check lower layer errno */
195     return(SMBlibE_BAD);
196
197   }
198
199   if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {  /* Process error */
200
201 #ifdef DEBUG
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));
205 #endif
206
207     SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
208     RFCNB_Free_Pkt(pkt);
209     SMBlib_errno = SMBlibE_Remote;
210     return(SMBlibE_BAD);
211
212   }
213   
214   if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
215
216 #ifdef DEBUG
217     fprintf(stderr, "None of our protocols was accepted ... ");
218 #endif
219
220     RFCNB_Free_Pkt(pkt);
221     SMBlib_errno = SMBlibE_NegNoProt;
222     return(SMBlibE_BAD);
223
224   }
225
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 ...                     */
228
229   Con_Handle -> prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
230   Con_Handle -> protocol = SMB_Figure_Protocol(Prots, prot);
231
232   if (Con_Handle -> protocol == SMB_P_Unknown) { /* No good ... */
233
234     RFCNB_Free_Pkt(pkt);
235     SMBlib_errno = SMBlibE_ProtUnknown;
236     return(SMBlibE_BAD);
237
238   }
239   
240   switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
241
242   case 0x01:      /* No more info ... */
243
244     break;
245
246   case 13:        /* Up to and including LanMan 2.1 */
247
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;
251
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);
259     
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);
263
264     p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
265
266     strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
267
268     break;
269
270   case 17:        /* NT LM 0.12 and LN LM 1.0 */
271
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;
275
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);
283
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);
287
288     strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
289
290     break;
291
292   default:
293
294 #ifdef DEBUG
295     fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
296     fprintf(stderr, "  wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
297 #endif
298
299     break;
300   }
301
302 #ifdef DEBUG
303   fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
304 #endif
305
306   RFCNB_Free_Pkt(pkt);
307   return(0);
308
309 }
310
311 /* Get our hostname */
312
313 void SMB_Get_My_Name(char *name, int len)
314
315 {
316   if (gethostname(name, len) < 0) { /* Error getting name */
317
318     strncpy(name, "unknown", len);
319
320     /* Should check the error */
321
322 #ifdef DEBUG
323     fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
324     perror("");
325 #endif
326
327   }
328
329   /* only keep the portion up to the first "." */
330
331
332 }