chiark / gitweb /
Commit 2.4.5-5 as unpacked
[inn-innduct.git] / authprogs / smbval / rfcnb-util.c
1 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
2
3    Version 1.0
4    RFCNB 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 #include "portable/socket.h"
29 #include <errno.h>
30 #include <netdb.h>
31
32 #include "rfcnb-priv.h"
33 #include "rfcnb-util.h"
34 #include "rfcnb-io.h"
35
36 #ifndef INADDR_NONE
37 # define INADDR_NONE -1
38 #endif
39
40 extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
41
42 /* Convert name and pad to 16 chars as needed */
43 /* Name 1 is a C string with null termination, name 2 may not be */
44 /* If SysName is true, then put a <00> on end, else space>       */
45
46 void RFCNB_CvtPad_Name(char *name1, char *name2)
47
48 { char c, c1, c2;
49   int i, len;
50
51   len = strlen(name1);
52
53   for (i = 0; i < 16; i++) {
54
55     if (i >= len) {
56
57      c1 = 'C'; c2 = 'A'; /* CA is a space */
58  
59     } else {
60
61       c = name1[i];
62       c1 = (char)((int)c/16 + (int)'A');
63       c2 = (char)((int)c%16 + (int)'A');
64     }
65
66     name2[i*2] = c1;
67     name2[i*2+1] = c2;
68
69   }
70
71   name2[32] = 0;   /* Put in the nll ...*/
72
73 }
74
75 /* Get a packet of size n */
76
77 struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
78
79 { RFCNB_Pkt *pkt;
80
81   if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
82
83     RFCNB_errno = RFCNBE_NoSpace;
84     RFCNB_saved_errno = errno;
85     return(NULL);
86
87   }
88
89   pkt -> next = NULL;
90   pkt -> len = n;
91
92   if (n == 0) return(pkt);
93
94   if ((pkt -> data = (char *)malloc(n)) == NULL) {
95
96     RFCNB_errno = RFCNBE_NoSpace;
97     RFCNB_saved_errno = errno;
98     free(pkt);
99     return(NULL);
100
101   }
102
103   return(pkt);
104
105 }
106
107 /* Free up a packet */
108
109 void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
110
111 { struct RFCNB_Pkt *pkt_next; char *data_ptr;
112
113   while (pkt != NULL) {
114
115     pkt_next = pkt -> next;
116
117     data_ptr = pkt -> data;
118
119     if (data_ptr != NULL)
120       free(data_ptr);
121
122     free(pkt);
123
124     pkt = pkt_next;
125
126   }
127
128 }
129
130 /* Resolve a name into an address */
131
132 int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
133
134 { int addr;         /* Assumes IP4, 32 bit network addresses */
135   struct hostent *hp;
136
137         /* Use inet_addr to try to convert the address */
138
139   if ((addr = inet_addr(host)) == INADDR_NONE) { /* Oh well, a good try :-) */
140
141         /* Now try a name look up with gethostbyname */
142
143     if ((hp = gethostbyname(host)) == NULL) { /* Not in DNS */
144
145         /* Try NetBIOS name lookup, how the hell do we do that? */
146
147       RFCNB_errno = RFCNBE_BadName;   /* Is this right? */
148       RFCNB_saved_errno = errno;
149       return(RFCNBE_Bad);
150
151     }
152     else {  /* We got a name */
153
154        memcpy((void *)Dest_IP, (void *)hp -> h_addr_list[0], sizeof(struct in_addr));
155
156     }
157   }
158   else { /* It was an IP address */
159
160     memcpy((void *)Dest_IP, (void *)&addr, sizeof(struct in_addr));
161
162   }
163
164   return 0;
165
166 }
167
168 /* Disconnect the TCP connection to the server */
169
170 int RFCNB_Close(int socket)
171
172 {
173
174   close(socket);
175
176   /* If we want to do error recovery, here is where we put it */
177
178   return 0;
179
180 }
181
182 /* Connect to the server specified in the IP address.
183    Not sure how to handle socket options etc.         */
184
185 int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
186
187 { struct sockaddr_in Socket;
188   int fd;
189
190   /* Create a socket */
191
192   if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
193
194     RFCNB_errno = RFCNBE_BadSocket;
195     RFCNB_saved_errno = errno;
196     return(RFCNBE_Bad);
197     } 
198
199   memset(&Socket, 0, sizeof(Socket));
200   memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
201
202   Socket.sin_port = htons(port);
203   Socket.sin_family = PF_INET;
204
205   /* Now connect to the destination */
206
207   if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
208
209     close(fd);
210     RFCNB_errno = RFCNBE_ConnectFailed;
211     RFCNB_saved_errno = errno;
212     return(RFCNBE_Bad);
213     }
214
215   return(fd);
216
217 }
218
219 /* handle the details of establishing the RFCNB session with remote 
220    end 
221
222 */
223
224 int RFCNB_Session_Req(struct RFCNB_Con *con, 
225                       char *Called_Name, 
226                       char *Calling_Name,
227                       bool *redirect,
228                       struct in_addr *Dest_IP,
229                       int * port)
230
231 { char *sess_pkt;
232
233   /* Response packet should be no more than 9 bytes, make 16 jic */
234
235   char resp[16];
236   int len;
237   struct RFCNB_Pkt *pkt, res_pkt;
238
239   /* We build and send the session request, then read the response */
240
241   pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
242
243   if (pkt == NULL) {
244
245     return(RFCNBE_Bad);  /* Leave the error that RFCNB_Alloc_Pkt gives) */
246
247   }
248
249   sess_pkt = pkt -> data;    /* Get pointer to packet proper */
250
251   sess_pkt[RFCNB_Pkt_Type_Offset]  = RFCNB_SESSION_REQUEST;
252   RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
253   sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
254   sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
255
256   RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
257   RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
258
259   /* Now send the packet */
260
261   if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
262
263     return(RFCNBE_Bad);       /* Should be able to write that lot ... */
264
265     }
266
267   res_pkt.data = resp;
268   res_pkt.len  = sizeof(resp);
269   res_pkt.next = NULL;
270
271   if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
272
273     return(RFCNBE_Bad);
274
275   }
276
277   /* Now analyze the packet ... */
278
279   switch (RFCNB_Pkt_Type(resp)) {
280
281     case RFCNB_SESSION_REJ:         /* Didnt like us ... too bad */
282
283       /* Why did we get rejected ? */
284     
285       switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
286
287       case 0x80: 
288         RFCNB_errno = RFCNBE_CallRejNLOCN;
289         break;
290       case 0x81:
291         RFCNB_errno = RFCNBE_CallRejNLFCN;
292         break;
293       case 0x82:
294         RFCNB_errno = RFCNBE_CallRejCNNP;
295         break;
296       case 0x83:
297         RFCNB_errno = RFCNBE_CallRejInfRes;
298         break;
299       case 0x8F:
300         RFCNB_errno = RFCNBE_CallRejUnSpec;
301         break;
302       default:
303         RFCNB_errno = RFCNBE_ProtErr;
304         break;
305       }
306
307       return(RFCNBE_Bad);
308       break;
309
310     case RFCNB_SESSION_ACK:        /* Got what we wanted ...      */
311
312       return(0);
313       break;
314
315     case RFCNB_SESSION_RETARGET:   /* Go elsewhere                */
316
317       *redirect = true;       /* Copy port and ip addr       */
318
319       memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
320       *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
321
322       return(0);
323       break;
324
325     default:  /* A protocol error */
326
327       RFCNB_errno = RFCNBE_ProtErr;
328       return(RFCNBE_Bad);
329       break;
330     }
331 }