3 * Server for user registration with Moira and Kerberos.
5 * This file handles the processing of requests for the register
8 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
9 * For copying and distribution information, please see the file
13 #include <mit-copyright.h>
15 #include <moira_site.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
32 #define NUM_REQUESTS_SAVED 100 /* Number of transactions to save */
33 #define CUR_REQ (requests[cur_request_index]) /* The current request */
34 #define NEXT_INDEX(x) (x == NUM_REQUESTS_SAVED - 1) ? 0 : (x + 1)
35 #define PREV_INDEX(x) (x == 0) ? (NUM_REQUESTS_SAVED - 1) : (x - 1)
37 static struct servent *sp; /* Service info from /etc/services */
38 static int s; /* Socket descriptor */
39 static struct sockaddr_in sin; /* Internet style socket address */
40 static int addrlen; /* Size of socket address (sin) */
42 /* In order to elegantly handle multiple retransmissions, an instance
43 of this structure will be retained for the last NUM_REQUESTS_SAVED
44 transactions with the client. */
46 char out_pkt[BUFSIZ]; /* Buffer for outgoing packet */
47 int out_pktlen; /* Length of outgoing packet */
48 U_32BIT seqno; /* Sequence number for packet transmission */
49 u_long ip_address; /* Internet address of client host */
50 u_short cl_port; /* Port number client used */
53 static struct request_save requests[NUM_REQUESTS_SAVED]; /* Saved packets */
54 static int cur_request_index = 0; /* Index to the current request */
56 void clear_req(struct request_save *req);
57 void req_initialize(void);
58 int handle_retransmitted(void);
59 void respond(int status, char *text);
60 void get_request(struct msg *message);
61 void report(int status, char *message);
62 int format_pkt(char *packet, int *pktlenp, U_32BIT seqno,
63 int cl_status, char *message);
64 int ureg_validate_char(char *s);
65 int parse_pkt(char *packet, int pktlen, struct msg *message);
66 u_long cur_req_sender(void);
68 void clear_req(struct request_save *req)
75 void req_initialize(void)
79 /* Get service information from /etc/services */
80 if (!(sp = getservbyname("moira_ureg", "udp")))
82 com_err(whoami, errno, " unknown service moira_ureg/udp");
86 /* Get an internet style datagram socket */
87 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
89 com_err(whoami, errno, " socket");
92 memset(&sin, 0, sizeof(sin));
94 sin.sin_family = AF_INET;
95 sin.sin_port = sp->s_port;
96 sin.sin_addr.s_addr = INADDR_ANY;
98 /* Bind a name to the socket */
99 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
101 com_err(whoami, errno, " bind");
105 for (i = 0; i < NUM_REQUESTS_SAVED; i++)
106 clear_req(&(requests[i]));
109 int handle_retransmitted(void)
111 int i; /* A counter */
112 int status = FALSE; /* Return status */
114 for (i = PREV_INDEX(cur_request_index); i != cur_request_index;
117 if ((requests[i].seqno == CUR_REQ.seqno) &&
118 (requests[i].ip_address == sin.sin_addr.s_addr) &&
119 (requests[i].cl_port == sin.sin_port))
120 /* This is a retransmitted packet */
123 sendto(s, requests[i].out_pkt, requests[i].out_pktlen,
124 0, (struct sockaddr *)&sin, addrlen);
132 /* This routine takes care of sending packets back to the client and
133 caching the necessary information for retransmission detection.
134 It is the only place in which cur_request_index should be
136 void respond(int status, char *text)
138 CUR_REQ.out_pktlen = sizeof(CUR_REQ.out_pkt);
140 if (format_pkt(CUR_REQ.out_pkt, &(CUR_REQ.out_pktlen),
141 CUR_REQ.seqno, status, text))
142 com_err(whoami, 0, "Client error message was truncated.");
143 sendto(s, CUR_REQ.out_pkt, CUR_REQ.out_pktlen, 0,
144 (struct sockaddr *)&sin, addrlen);
146 cur_request_index = NEXT_INDEX(cur_request_index);
149 void get_request(struct msg *message)
151 static char packet[BUFSIZ]; /* Buffer for incoming packet */
152 int pktlen; /* Length of incoming packet */
153 int status = FAILURE; /* Error status */
155 /* Sit around waiting for requests from the client. */
158 com_err(whoami, 0, "*** Ready for next request ***");
159 addrlen = sizeof(sin);
160 /* Receive a packet */
161 if ((pktlen = recvfrom(s, packet, sizeof(packet), 0,
162 (struct sockaddr *)&sin, &addrlen)) < 0)
164 com_err(whoami, errno, " recvfrom");
165 /* Don't worry if error is interrupted system call. */
171 /* Store available information */
173 CUR_REQ.ip_address = sin.sin_addr.s_addr;
174 CUR_REQ.cl_port = sin.sin_port;
176 /* Parse a request packet and save sequence number */
177 if ((status = parse_pkt(packet, pktlen, message)) != SUCCESS)
179 /* If error, format packet to send back to the client */
180 respond(status, NULL);
184 /* Check for retransmitted packet. handle_retransmitted()
185 returns true if it handled a retransmitted packet. */
186 if (!handle_retransmitted())
192 void report(int status, char *message)
194 respond(status, message);
197 /* This routine prepares a packet to send back to the client. A
198 non-zero return status means that the client error message was
200 int format_pkt(char *packet, int *pktlenp, U_32BIT seqno,
201 int cl_status, char *message)
203 int len; /* Amount of message to send */
204 int status = SUCCESS; /* Return status */
206 /* Convert byte order to network byte order */
207 U_32BIT vers = htonl((U_32BIT)CUR_UREG_VERSION);
208 cl_status = htonl((U_32BIT)cl_status);
209 /* Put current user registration protocol version into the packet */
210 memcpy(packet, &vers, sizeof(U_32BIT));
211 /* Put sequence number into the packet */
212 memcpy(packet + sizeof(U_32BIT), &seqno, sizeof(U_32BIT));
213 /* Put error status into the packet */
214 memcpy(packet + 2 * sizeof(U_32BIT), &cl_status, sizeof(U_32BIT));
216 /* Find out how much of the message to copy; truncate if too short. */
217 /* How much room is there left? */
218 len = *pktlenp - sizeof(U_32BIT) * 3;
221 if (len < strlen(message) + 1) /* Room for null terminator */
223 status = FAILURE; /* Message was truncated */
224 /* Truncate the message */
225 message[len - 1] = '\0';
228 /* Copy the message into the packet */
229 strcpy(packet + 3 * sizeof(U_32BIT), message);
230 *pktlenp = 3 * sizeof(U_32BIT) + strlen(message);
235 /* The ureg_validate_char variable and routine were taken verbatim
236 out of server/qsupport.qc where they are called
237 validate_chars. At some point, it may be desirable
238 to put this functionality in one place. */
240 /* ureg_validate_char: verify that there are no illegal characters in
241 * the string. Legal characters are printing chars other than
242 * ", *, ?, \, [ and ].
244 static int illegalchars[] = {
245 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
246 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
247 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
252 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
253 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
254 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
255 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
256 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
257 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
258 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
263 int ureg_validate_char(char *s)
267 if (illegalchars[(int)*s++])
273 /* This routine checks a packet and puts the information in it in
274 a structure if it is valid. It also saves the sequence number
275 in the list of saved requests. */
276 int parse_pkt(char *packet, int pktlen, struct msg *message)
278 int status = SUCCESS; /* Error status */
280 com_err(whoami, 0, "Packet received");
282 if (pktlen < sizeof(U_32BIT))
283 status = UREG_BROKEN_PACKET;
284 if (status == SUCCESS)
286 /* Extract the user registration protocol version from the packet */
287 memcpy(&message->version, packet, sizeof(long));
288 /* Convert byte order from network to host */
289 message->version = ntohl(message->version);
291 if (message->version != CUR_UREG_VERSION)
292 status = UREG_WRONG_VERSION;
295 if (status == SUCCESS)
297 packet += sizeof(U_32BIT);
298 pktlen -= sizeof(U_32BIT);
300 if (pktlen < sizeof(U_32BIT))
301 status = UREG_BROKEN_PACKET;
304 if (status == SUCCESS)
306 /* Extract the sequence number from the packet */
307 memcpy(&CUR_REQ.seqno, packet, sizeof(long));
309 packet += sizeof(U_32BIT);
310 pktlen -= sizeof(U_32BIT);
312 if (pktlen < sizeof(U_32BIT))
313 status = UREG_BROKEN_PACKET;
316 if (status == SUCCESS)
318 /* Extract the request from the packet */
319 memcpy(&message->request, packet, sizeof(U_32BIT));
320 message->request = ntohl(message->request);
321 packet += sizeof(U_32BIT);
322 pktlen -= sizeof(U_32BIT);
324 /* Make sure that the packet contains only valid characters up
326 if (ureg_validate_char(packet) != SUCCESS)
328 com_err(whoami, 0, "Packet contains invalid characters.");
329 status = UREG_USER_NOT_FOUND;
333 /* Extract first name from the packet */
334 message->first = packet;
336 /* Scan forward until null appears in the packet or there
337 is no more packet! */
338 for (; *packet && pktlen > 0; --pktlen, ++packet)
341 status = UREG_BROKEN_PACKET;
345 if (status == SUCCESS)
347 /* Skip over the null */
350 if (ureg_validate_char(packet) != SUCCESS)
352 com_err(whoami, 0, "Packet contains invalid characters.");
353 status = UREG_USER_NOT_FOUND;
357 /* Extract last name from the packet */
358 message->last = packet;
360 for (; *packet && pktlen > 0; --pktlen, ++packet)
363 status = UREG_BROKEN_PACKET;
367 if (status == SUCCESS)
372 status = UREG_BROKEN_PACKET;
375 /* Extract encrypted information from packet */
376 message->encrypted = packet;
377 message->encrypted_len = pktlen;
379 if (status == SUCCESS)
381 com_err(whoami, status, "Request %d for %s %s", message->request,
382 message->first, message->last);
385 com_err(whoami, status, " - parse packet failed.");
391 u_long cur_req_sender(void)
393 return CUR_REQ.ip_address;