]> andersk Git - moira.git/blob - reg_svr/requests.c
NULL != ""
[moira.git] / reg_svr / requests.c
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
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>.
9  *
10  *      Server for user registration with Moira 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
25 #include <mit-copyright.h>
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>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <netdb.h>
37 #include "moira.h"
38 #include "moira_site.h"
39 #include "reg_svr.h"
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     memset(&sin, 0, 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, (struct sockaddr *)&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, (struct sockaddr *)&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,
147                   (struct sockaddr *)&sin, addrlen);
148
149     cur_request_index = NEXT_INDEX(cur_request_index);
150 }
151
152 void get_request(message)
153   struct msg *message;          /* Will contain formatted packet information */
154 {
155     static char packet[BUFSIZ]; /* Buffer for incoming packet */
156     int pktlen;                 /* Length of incoming packet */
157     int status = FAILURE;       /* Error status */
158
159     /* Sit around waiting for requests from the client. */
160     for (;;)
161     {
162         com_err(whoami, 0, "*** Ready for next request ***");
163         addrlen = sizeof(sin);
164         /* Receive a packet */
165         if ((pktlen = recvfrom(s,packet,sizeof(packet),0,
166                                (struct sockaddr *)&sin,&addrlen)) < 0) 
167         {
168             com_err(whoami, errno, " recvfrom");
169             /* Don't worry if error is interrupted system call. */
170             if (errno == EINTR) continue;
171             exit(1);
172         }
173         
174         /* Store available information */
175         CUR_REQ.seqno = 0;
176         CUR_REQ.ip_address = sin.sin_addr.s_addr;
177         CUR_REQ.cl_port = sin.sin_port;
178
179         /* Parse a request packet and save sequence number */
180         if ((status = parse_pkt(packet, pktlen, message)) 
181             != SUCCESS) 
182         {
183             /* If error, format packet to send back to the client */
184             respond(status, (char *)NULL);
185         }
186         else
187         {
188             /* Check for retransmitted packet.  handle_retransmitted() 
189                returns true if it handled a retransmitted packet. */
190             if (!handle_retransmitted())
191                 break;
192         }
193     }
194 }
195
196 void report(status, message)
197   int status;
198   char * message;
199 {
200     respond(status, message);
201 }
202
203 int format_pkt(packet, pktlenp, seqno, cl_status, message)
204   char *packet;                 /* Packet buffer */
205   int *pktlenp;                 /* Pointer to packet size */
206   U_32BIT seqno;                /* Sequence number */
207   int cl_status;                /* Error status to return to client */
208   char *message;                /* Error message to return to client */
209   /* This routine prepares a packet to send back to the client.  A 
210      non-zero return status means that the client error message was 
211      truncated. */
212 {
213     int len;                    /* Amount of message to send */
214     int status = SUCCESS;       /* Return status */
215
216     /* Convert byte order to network byte order */
217     U_32BIT vers = htonl((U_32BIT)CUR_UREG_VERSION);
218     cl_status = htonl((U_32BIT)cl_status);
219     /* Put current user registration protocol version into the packet */
220     memcpy(packet, &vers, sizeof(U_32BIT));
221     /* Put sequence number into the packet */
222     memcpy(packet+sizeof(U_32BIT), &seqno, sizeof(U_32BIT));
223     /* Put error status into the packet */
224     memcpy(packet+ 2*sizeof(U_32BIT), &cl_status, sizeof(U_32BIT));
225     
226     /* Find out how much of the message to copy; truncate if too short. */
227     /* How much room is there left? */
228     len = *pktlenp - sizeof(U_32BIT)*3;
229     if (message == NULL) message = "";
230     if (len < strlen(message) + 1) /* Room for null terminator */
231     {
232         status = FAILURE;       /* Message was truncated */
233         /* Truncate the message */
234         message[len-1] = '\0';
235     }
236
237     /* Copy the message into the packet */
238     (void) strcpy(packet+3*sizeof(U_32BIT), message);
239     *pktlenp = 3*sizeof(U_32BIT) + strlen(message);
240     
241     return status;
242 }
243
244 /* The ureg_validate_char variable and routine were taken verbatim 
245    out of server/qsupport.qc where they are called
246    validate_chars.  At some point, it may be desirable
247    to put this functionality in one place. */
248
249 /* ureg_validate_char: verify that there are no illegal characters in
250  * the string.  Legal characters are printing chars other than 
251  * ", *, ?, \, [ and ].
252  */
253 static int illegalchars[] = {
254     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
255     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
256     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
257     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
258     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
259     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
260     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
261     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
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     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
268     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
269     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
270 };
271
272 ureg_validate_char(s)
273 register char *s;
274 {
275     while (*s)
276       if (illegalchars[*s++])
277         return(FAILURE);
278     return(SUCCESS);
279 }
280
281 parse_pkt(packet, pktlen, message)
282   char *packet;
283   int pktlen;
284   struct msg *message;
285   /* This routine checks a packet and puts the information in it in
286      a structure if it is valid.  It also saves the sequence number
287      in the list of saved requests. */
288 {
289     int status = SUCCESS;       /* Error status */
290
291     com_err(whoami,0,"Packet received");
292
293     if (pktlen < sizeof(U_32BIT)) status = UREG_BROKEN_PACKET;
294     if (status == SUCCESS)
295     {
296         /* Extract the user registration protocol version from the packet */
297         memcpy(&message->version, packet, sizeof(long));
298         /* Convert byte order from network to host */
299         message->version = ntohl(message->version);
300         /* Verify version */
301         if (message->version != CUR_UREG_VERSION) 
302             status = UREG_WRONG_VERSION;
303     }
304
305     if (status == SUCCESS)
306     {
307         packet += sizeof(U_32BIT);
308         pktlen -= sizeof(U_32BIT);
309         
310         if (pktlen < sizeof(U_32BIT))
311             status = UREG_BROKEN_PACKET;
312     }
313
314     if (status == SUCCESS)
315     {
316         /* Extract the sequence number from the packet */
317         memcpy(&CUR_REQ.seqno, packet, sizeof(long));
318         
319         packet += sizeof(U_32BIT);
320         pktlen -= sizeof(U_32BIT);
321         
322         if (pktlen < sizeof(U_32BIT))
323             status = UREG_BROKEN_PACKET;
324     }
325
326     if (status == SUCCESS)
327     {
328         /* Extract the request from the packet */
329         memcpy(&message->request, packet, sizeof(U_32BIT));
330         message->request = ntohl(message->request);
331         packet += sizeof(U_32BIT);
332         pktlen -= sizeof(U_32BIT);
333         
334         /* Make sure that the packet contains only valid characters up 
335            to the next null */
336         if (ureg_validate_char(packet) != SUCCESS)
337         {
338             com_err(whoami,0,"Packet contains invalid characters.");
339             status = UREG_USER_NOT_FOUND;
340         }
341         else
342         {
343             /* Extract first name from the packet */
344             message->first = packet;
345             
346             /* Scan forward until null appears in the packet or there
347                is no more packet! */
348             for (; *packet && pktlen > 0; --pktlen, ++packet) continue;
349             if (pktlen <= 0) 
350                 status = UREG_BROKEN_PACKET;
351         }
352     }
353     
354     if (status == SUCCESS)
355     {
356         /* Skip over the null */
357         packet++, pktlen--;
358         
359         if (ureg_validate_char(packet) != SUCCESS)
360         {
361             com_err(whoami,0,"Packet contains invalid characters.");
362             status = UREG_USER_NOT_FOUND;
363         }
364         else
365         {
366             /* Extract last name from the packet */
367             message->last = packet;
368             
369             for (; *packet && pktlen > 0; --pktlen, ++packet) continue;
370             if (pktlen <= 0)
371                 status = UREG_BROKEN_PACKET;
372         }
373     }
374
375     if (status == SUCCESS)
376     {
377         packet++, pktlen--;
378         
379         if (pktlen <= 0)
380             status = UREG_BROKEN_PACKET;
381     }
382
383     /* Extract encrypted information from packet */
384     message->encrypted = packet;
385     message->encrypted_len = pktlen;
386     
387     if (status == SUCCESS)
388     {
389 #ifdef DEBUG
390         com_err(whoami,status,"%s\n%s%d\n%s%d\n%s%s\n%s%s",
391                 "Packet parsed successfully.  Packet contains:",
392                 "   Protocol version: ",message->version,
393                 "   Request: ",message->request,
394                 "   First name: ",message->first,
395                 "   Last name: ",message->last);
396 #else /* DEBUG */
397         com_err(whoami,status,"Request %d for %s %s",message->request,
398                 message->first,message->last);
399 #endif DEBUG    
400     }
401     else
402         com_err(whoami,status," - parse packet failed.");
403
404     return status;
405 }
406
407
408 u_long cur_req_sender()
409 {
410     return (CUR_REQ.ip_address);
411 }
This page took 0.065589 seconds and 5 git commands to generate.