]>
Commit | Line | Data |
---|---|---|
9a83b251 | 1 | /* |
2 | * $Source$ | |
3 | * $Author$ | |
4 | * $Header$ | |
5 | * | |
0a5ff702 | 6 | * Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology |
7 | * For copying and distribution information, please see the file | |
8 | * <mit-copyright.h>. | |
9a83b251 | 9 | * |
10 | * Server for user registration with SMS and Kerberos. | |
11 | * | |
12 | * This file handles the processing of requests for the register | |
13 | * server. | |
14 | */ | |
15 | ||
16 | #ifndef lint | |
17 | static char *rcsid_requests_c = "$Header$"; | |
18 | #endif lint | |
19 | ||
20 | /* | |
21 | * Before you add anything to the list of things that are #included and | |
22 | * #defined, make sure that it is not already done in reg_svr.h | |
23 | */ | |
24 | ||
0a5ff702 | 25 | #include <mit-copyright.h> |
952aa193 | 26 | #include <stdio.h> |
27 | #include <strings.h> | |
28 | #include <ctype.h> | |
29 | #include <sys/types.h> | |
30 | #include <sys/file.h> | |
31 | #include <krb.h> | |
32 | #include <des.h> | |
33 | #include <errno.h> | |
9a83b251 | 34 | #include <sys/socket.h> |
35 | #include <netinet/in.h> | |
36 | #include <netdb.h> | |
952aa193 | 37 | #include "sms.h" |
38 | #include "sms_app.h" | |
39 | #include "reg_svr.h" | |
9a83b251 | 40 | |
41 | #define NUM_REQUESTS_SAVED 100 /* Number of transactions to save */ | |
42 | #define CUR_REQ (requests[cur_request_index]) /* The current request */ | |
43 | #define NEXT_INDEX(x) (x == NUM_REQUESTS_SAVED - 1) ? 0 : (x + 1) | |
44 | #define PREV_INDEX(x) (x == 0) ? (NUM_REQUESTS_SAVED - 1) : (x - 1) | |
45 | ||
46 | static struct servent *sp; /* Service info from /etc/services */ | |
47 | static int s; /* Socket descriptor */ | |
48 | static struct sockaddr_in sin; /* Internet style socket address */ | |
49 | static int addrlen; /* Size of socket address (sin) */ | |
50 | ||
51 | /* In order to elegantly handle multiple retransmissions, an instance | |
52 | of this structure will be retained for the last NUM_REQUESTS_SAVED | |
53 | transactions with the client. */ | |
54 | struct request_save { | |
55 | char out_pkt[BUFSIZ]; /* Buffer for outgoing packet */ | |
56 | int out_pktlen; /* Length of outgoing packet */ | |
57 | U_32BIT seqno; /* Sequence number for packet transmission */ | |
58 | u_long ip_address; /* Internet address of client host */ | |
59 | u_short cl_port; /* Port number client used */ | |
60 | }; | |
61 | ||
62 | static struct request_save requests[NUM_REQUESTS_SAVED]; /* Saved packets */ | |
63 | static int cur_request_index = 0; /* Index to the current request */ | |
64 | ||
65 | void clear_req(req) | |
66 | struct request_save *req; | |
67 | { | |
68 | req->seqno = 0; | |
69 | req->ip_address = 0; | |
70 | req->cl_port = 0; | |
71 | } | |
72 | ||
73 | void req_initialize() | |
74 | { | |
75 | register int i; | |
76 | ||
77 | /* Get service information from /etc/services */ | |
78 | if ((sp = getservbyname("sms_ureg", "udp")) == NULL) | |
79 | { | |
80 | com_err(whoami, errno, " unknown service sms_ureg/udp"); | |
81 | exit(1); | |
82 | } | |
83 | ||
84 | /* Get an internet style datagram socket */ | |
85 | if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) | |
86 | { | |
87 | com_err(whoami,errno," socket"); | |
88 | exit(1); | |
89 | } | |
90 | bzero((char *)&sin,(int)sizeof(sin)); | |
91 | ||
92 | sin.sin_family = AF_INET; | |
93 | sin.sin_port = sp->s_port; | |
94 | sin.sin_addr.s_addr = INADDR_ANY; | |
95 | ||
96 | /* Bind a name to the socket */ | |
97 | if (bind(s, &sin, sizeof(sin)) < 0) | |
98 | { | |
99 | com_err(whoami,errno," bind"); | |
100 | exit(1); | |
101 | } | |
102 | ||
103 | for (i = 0; i < NUM_REQUESTS_SAVED; i++) | |
104 | clear_req(&(requests[i])); | |
105 | } | |
106 | ||
107 | int handle_retransmitted() | |
108 | { | |
109 | register int i; /* A counter */ | |
110 | int status = FALSE; /* Return status */ | |
111 | ||
112 | for (i = PREV_INDEX(cur_request_index); i != cur_request_index; | |
113 | i = PREV_INDEX(i)) | |
114 | { | |
115 | if ((requests[i].seqno == CUR_REQ.seqno) && | |
116 | (requests[i].ip_address == sin.sin_addr.s_addr) && | |
117 | (requests[i].cl_port == sin.sin_port)) | |
118 | /* This is a retransmitted packet */ | |
119 | { | |
120 | #ifdef DEBUG | |
121 | com_err(whoami, 0, "Retransmitted packet detected."); | |
122 | #endif | |
123 | status = TRUE; | |
124 | (void) sendto(s, requests[i].out_pkt, requests[i].out_pktlen, | |
125 | 0, &sin, addrlen); | |
126 | break; | |
127 | } | |
128 | } | |
129 | ||
130 | return status; | |
131 | } | |
132 | ||
133 | void respond(status,text) | |
134 | int status; /* Return status for the client */ | |
135 | char *text; /* Text for the client */ | |
136 | /* This routine takes care of sending packets back to the client and | |
137 | caching the necessary information for retransmission detection. | |
138 | It is the only place in which cur_request_index should be | |
139 | changed. */ | |
140 | { | |
141 | CUR_REQ.out_pktlen = sizeof(CUR_REQ.out_pkt); | |
142 | ||
143 | if (format_pkt(CUR_REQ.out_pkt, &(CUR_REQ.out_pktlen), | |
144 | CUR_REQ.seqno, status, text)) | |
145 | com_err(whoami,0,"Client error message was truncated."); | |
146 | (void) sendto(s, CUR_REQ.out_pkt, CUR_REQ.out_pktlen, 0, &sin, addrlen); | |
147 | ||
148 | cur_request_index = NEXT_INDEX(cur_request_index); | |
149 | } | |
150 | ||
151 | void get_request(message) | |
152 | struct msg *message; /* Will contain formatted packet information */ | |
153 | { | |
154 | static char packet[BUFSIZ]; /* Buffer for incoming packet */ | |
155 | int pktlen; /* Length of incoming packet */ | |
156 | int status = FAILURE; /* Error status */ | |
157 | ||
158 | /* Sit around waiting for requests from the client. */ | |
159 | for (;;) | |
160 | { | |
161 | com_err(whoami, 0, "*** Ready for next request ***"); | |
162 | addrlen = sizeof(sin); | |
163 | /* Receive a packet */ | |
164 | if ((pktlen = recvfrom(s,packet,sizeof(packet),0,&sin,&addrlen)) < 0) | |
165 | { | |
166 | com_err(whoami, errno, " recvfrom"); | |
167 | /* Don't worry if error is interrupted system call. */ | |
168 | if (errno == EINTR) continue; | |
169 | exit(1); | |
170 | } | |
171 | ||
172 | /* Store available information */ | |
173 | CUR_REQ.seqno = 0; | |
174 | CUR_REQ.ip_address = sin.sin_addr.s_addr; | |
175 | CUR_REQ.cl_port = sin.sin_port; | |
176 | ||
177 | /* Parse a request packet and save sequence number */ | |
178 | if ((status = parse_pkt(packet, pktlen, message)) | |
179 | != SUCCESS) | |
180 | { | |
181 | /* If error, format packet to send back to the client */ | |
182 | respond(status, (char *)NULL); | |
183 | } | |
184 | else | |
185 | { | |
186 | /* Check for retransmitted packet. handle_retransmitted() | |
187 | returns true if it handled a retransmitted packet. */ | |
188 | if (!handle_retransmitted()) | |
189 | break; | |
190 | } | |
191 | } | |
192 | } | |
193 | ||
194 | void report(status, message) | |
195 | int status; | |
196 | char * message; | |
197 | { | |
198 | respond(status, message); | |
199 | } | |
200 | ||
201 | int format_pkt(packet, pktlenp, seqno, cl_status, message) | |
202 | char *packet; /* Packet buffer */ | |
203 | int *pktlenp; /* Pointer to packet size */ | |
204 | U_32BIT seqno; /* Sequence number */ | |
205 | int cl_status; /* Error status to return to client */ | |
206 | char *message; /* Error message to return to client */ | |
207 | /* This routine prepares a packet to send back to the client. A | |
208 | non-zero return status means that the client error message was | |
209 | truncated. */ | |
210 | { | |
211 | int len; /* Amount of message to send */ | |
212 | int status = SUCCESS; /* Return status */ | |
213 | ||
214 | /* Convert byte order to network byte order */ | |
215 | U_32BIT vers = htonl((U_32BIT)CUR_UREG_VERSION); | |
216 | cl_status = htonl((U_32BIT)cl_status); | |
217 | /* Put current user registration protocol version into the packet */ | |
218 | bcopy((char *)&vers, packet, sizeof(U_32BIT)); | |
219 | /* Put sequence number into the packet */ | |
220 | bcopy((char *)&seqno, packet+sizeof(U_32BIT), sizeof(U_32BIT)); | |
221 | /* Put error status into the packet */ | |
222 | bcopy((char *)&cl_status, packet+ 2*sizeof(U_32BIT), sizeof(U_32BIT)); | |
223 | ||
224 | /* Find out how much of the message to copy; truncate if too short. */ | |
225 | /* How much room is there left? */ | |
226 | len = *pktlenp - sizeof(U_32BIT)*3; | |
227 | if (len < strlen(message) + 1) /* Room for null terminator */ | |
228 | { | |
229 | status = FAILURE; /* Message was truncated */ | |
230 | /* Truncate the message */ | |
231 | message[len-1] = NULL; | |
232 | } | |
233 | ||
234 | /* Copy the message into the packet */ | |
235 | (void) strcpy(packet+3*sizeof(U_32BIT), message); | |
236 | *pktlenp = 3*sizeof(U_32BIT) + strlen(message); | |
237 | ||
238 | return status; | |
239 | } | |
240 | ||
241 | /* The ureg_validate_char variable and routine were taken verbatim | |
242 | out of server/qsupport.qc where they are called | |
243 | validate_chars. At some point, it may be desirable | |
244 | to put this functionality in one place. */ | |
245 | ||
246 | /* ureg_validate_char: verify that there are no illegal characters in | |
247 | * the string. Legal characters are printing chars other than | |
248 | * ", *, ?, \, [ and ]. | |
249 | */ | |
250 | static int illegalchars[] = { | |
251 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */ | |
252 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */ | |
253 | 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */ | |
254 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */ | |
255 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */ | |
256 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */ | |
257 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */ | |
258 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */ | |
259 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
260 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
261 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
262 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
263 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
264 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
265 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
266 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
267 | }; | |
268 | ||
269 | ureg_validate_char(s) | |
270 | register char *s; | |
271 | { | |
272 | while (*s) | |
273 | if (illegalchars[*s++]) | |
274 | return(FAILURE); | |
275 | return(SUCCESS); | |
276 | } | |
277 | ||
278 | parse_pkt(packet, pktlen, message) | |
279 | char *packet; | |
280 | int pktlen; | |
281 | struct msg *message; | |
282 | /* This routine checks a packet and puts the information in it in | |
283 | a structure if it is valid. It also saves the sequence number | |
284 | in the list of saved requests. */ | |
285 | { | |
286 | int status = SUCCESS; /* Error status */ | |
287 | ||
288 | com_err(whoami,0,"Packet received"); | |
289 | ||
290 | if (pktlen < sizeof(U_32BIT)) status = UREG_BROKEN_PACKET; | |
291 | if (status == SUCCESS) | |
292 | { | |
293 | /* Extract the user registration protocol version from the packet */ | |
294 | bcopy(packet, (char *)&message->version, sizeof(long)); | |
295 | /* Convert byte order from network to host */ | |
296 | message->version = ntohl(message->version); | |
297 | /* Verify version */ | |
298 | if (message->version != CUR_UREG_VERSION) | |
299 | status = UREG_WRONG_VERSION; | |
300 | } | |
301 | ||
302 | if (status == SUCCESS) | |
303 | { | |
304 | packet += sizeof(U_32BIT); | |
305 | pktlen -= sizeof(U_32BIT); | |
306 | ||
307 | if (pktlen < sizeof(U_32BIT)) | |
308 | status = UREG_BROKEN_PACKET; | |
309 | } | |
310 | ||
311 | if (status == SUCCESS) | |
312 | { | |
313 | /* Extract the sequence number from the packet */ | |
314 | bcopy(packet, (char *)&CUR_REQ.seqno, sizeof(long)); | |
315 | ||
316 | packet += sizeof(U_32BIT); | |
317 | pktlen -= sizeof(U_32BIT); | |
318 | ||
319 | if (pktlen < sizeof(U_32BIT)) | |
320 | status = UREG_BROKEN_PACKET; | |
321 | } | |
322 | ||
323 | if (status == SUCCESS) | |
324 | { | |
325 | /* Extract the request from the packet */ | |
326 | bcopy(packet, (char *)(&message->request), sizeof(U_32BIT)); | |
327 | message->request = ntohl(message->request); | |
328 | packet += sizeof(U_32BIT); | |
329 | pktlen -= sizeof(U_32BIT); | |
330 | ||
331 | /* Make sure that the packet contains only valid characters up | |
332 | to the next null */ | |
333 | if (ureg_validate_char(packet) != SUCCESS) | |
334 | { | |
335 | com_err(whoami,0,"Packet contains invalid characters."); | |
336 | status = UREG_USER_NOT_FOUND; | |
337 | } | |
338 | else | |
339 | { | |
340 | /* Extract first name from the packet */ | |
341 | message->first = packet; | |
342 | ||
343 | /* Scan forward until null appears in the packet or there | |
344 | is no more packet! */ | |
345 | for (; *packet && pktlen > 0; --pktlen, ++packet) continue; | |
346 | if (pktlen <= 0) | |
347 | status = UREG_BROKEN_PACKET; | |
348 | } | |
349 | } | |
350 | ||
351 | if (status == SUCCESS) | |
352 | { | |
353 | /* Skip over the null */ | |
354 | packet++, pktlen--; | |
355 | ||
356 | if (ureg_validate_char(packet) != SUCCESS) | |
357 | { | |
358 | com_err(whoami,0,"Packet contains invalid characters."); | |
359 | status = UREG_USER_NOT_FOUND; | |
360 | } | |
361 | else | |
362 | { | |
363 | /* Extract last name from the packet */ | |
364 | message->last = packet; | |
365 | ||
366 | for (; *packet && pktlen > 0; --pktlen, ++packet) continue; | |
367 | if (pktlen <= 0) | |
368 | status = UREG_BROKEN_PACKET; | |
369 | } | |
370 | } | |
371 | ||
372 | if (status == SUCCESS) | |
373 | { | |
374 | packet++, pktlen--; | |
375 | ||
376 | if (pktlen <= 0) | |
377 | status = UREG_BROKEN_PACKET; | |
378 | } | |
379 | ||
380 | /* Extract encrypted information from packet */ | |
381 | message->encrypted = packet; | |
382 | message->encrypted_len = pktlen; | |
383 | ||
384 | if (status == SUCCESS) | |
385 | { | |
386 | #ifdef DEBUG | |
387 | com_err(whoami,status,"%s\n%s%d\n%s%d\n%s%s\n%s%s", | |
388 | "Packet parsed successfully. Packet contains:", | |
389 | " Protocol version: ",message->version, | |
390 | " Request: ",message->request, | |
391 | " First name: ",message->first, | |
392 | " Last name: ",message->last); | |
393 | #else /* DEBUG */ | |
394 | com_err(whoami,status,"Request %d for %s %s",message->request, | |
395 | message->first,message->last); | |
396 | #endif DEBUG | |
397 | } | |
398 | else | |
399 | com_err(whoami,status," - parse packet failed."); | |
400 | ||
401 | return status; | |
402 | } | |
403 | ||
404 | /* | |
405 | * Local Variables: | |
406 | * mode: c | |
407 | * c-argdecl-indent: 2 | |
408 | * c-brace-offset: -4 | |
409 | * c-continued-statement-offset: 4 | |
410 | * c-indent-level: 4 | |
411 | * c-label-offset: -2 | |
412 | * End: | |
413 | */ |