]> andersk Git - moira.git/blame - reg_svr/reg_svr.pc
Assign EXCHANGE poboxes to all incoming students.
[moira.git] / reg_svr / reg_svr.pc
CommitLineData
b50f996d 1/* $Id$
2 *
3 * Server for user registration with Moira and Kerberos.
4 *
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 */
9
10#include <mit-copyright.h>
11#include <moira.h>
12#include <mr_private.h>
13#include <moira_schema.h>
14#include <moira_site.h>
15#include "reg_svr.h"
16
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <sys/stat.h>
20#include <sys/time.h>
21#include <sys/utsname.h>
22
23#include <netinet/in.h>
24#include <netdb.h>
25
26#include <ctype.h>
27#include <errno.h>
28#include <signal.h>
29#include <stdarg.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35#include <com_err.h>
36#include <krb.h>
37
38EXEC SQL INCLUDE sqlca;
39
40RCSID("$Header$");
41
42char *whoami, *hostname, *shorthostname;
43
44char *find_usernames(char *first, char *middle, char *last);
276949c1 45int check_username_available(char *username);
b50f996d 46void fixname(char *name);
47int register_user(int uid, char *username);
48void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar);
49void sigshut(int);
50
51reg_client *cl = NULL;
52enum { RS_RUNNING, RS_SLEEPING, RS_EXITING } state = RS_RUNNING;
53
54int main(int argc, char **argv)
55{
56 int listener, nfds, i, clientid = 0;
57 fd_set readfds, xreadfds;
58 reg_client *clients;
59 int nclients, clientssize;
60 long status;
61 char *db = "moira";
62 struct utsname uts;
63 struct hostent *h;
64 struct sigaction sa;
65 struct stat st;
66
67 whoami = strrchr(argv[0], '/');
68 whoami = whoami ? whoami + 1 : argv[0];
69
70 set_com_err_hook(mr_com_err);
71
72 /* Read keys */
73 if (!read_rsa_key())
74 {
75 com_err(whoami, errno, "reading RSA key");
76 exit(1);
77 }
78 if (!read_hmac_key())
79 {
80 com_err(whoami, errno, "reading HMAC key");
81 exit(1);
82 }
83
84 /* Read error messages */
85 if (!read_errors())
86 {
87 com_err(whoami, errno, "reading error messages");
88 exit(1);
89 }
90
91 /* Connect to database */
92 EXEC SQL CONNECT :db IDENTIFIED BY :db;
93 if (sqlca.sqlcode)
94 {
95 char err_msg[256];
96 int bufsize = 256, msglength = 0;
97
98 sqlglm(err_msg, &bufsize, &msglength);
99 err_msg[msglength] = 0;
100 com_err(whoami, 0, "SQL error connecting to DBMS:\n%s", err_msg);
101 exit(1);
102 }
103
104 /* Get my hostname */
105 uname(&uts);
106 h = gethostbyname(uts.nodename);
107 if (!h)
108 {
109 com_err(whoami, 0, "Couldn't resolve hostname %s", uts.nodename);
110 exit(1);
111 }
112 hostname = lowercase(xstrdup(h->h_name));
113 shorthostname = xstrdup(hostname);
114 if (strchr(shorthostname, '.'))
115 *strchr(shorthostname, '.') = '\0';
116
117 /* Initialize kerberos */
118 status = init_kerberos();
119 if (status)
120 {
121 com_err(whoami, status, "initializing kerberos library");
122 exit(1);
123 }
124
125 /* Set up listening socket. */
126 listener = mr_listen("moira_ureg");
127 if (listener < 0)
128 {
129 com_err(whoami, errno, "couldn't create listening socket");
130 exit(1);
131 }
132 FD_ZERO(&xreadfds);
133 FD_SET(listener, &xreadfds);
134 nfds = listener + 1;
135
136 /* Initialize client array. */
137 nclients = 0;
138 clientssize = 5;
139 clients = malloc(clientssize * sizeof(reg_client));
140 if (!clients)
141 {
142 com_err(whoami, errno, "creating client array");
143 exit(1);
144 }
145
146 /* Set up signal handlers */
147 sa.sa_flags = 0;
148 sigemptyset(&sa.sa_mask);
149 sa.sa_handler = sigshut;
150 sigaction(SIGTERM, &sa, NULL);
151 sigaction(SIGINT, &sa, NULL);
152 sigaction(SIGHUP, &sa, NULL);
153 sa.sa_handler = SIG_IGN;
154 sigaction(SIGPIPE, &sa, NULL);
155
156 com_err(whoami, 0, "started (pid %d)", getpid());
157 com_err(whoami, 0, rcsid);
158
159 /* Main loop */
160 while (state != RS_EXITING)
161 {
162 if (state == RS_RUNNING && stat(MOIRA_MOTD_FILE, &st) == 0)
163 {
9dcee057 164 state = RS_SLEEPING;
b50f996d 165 com_err(whoami, 0, "found motd. reg_svr is sleeping");
166 }
167 else if (state == RS_SLEEPING && stat(MOIRA_MOTD_FILE, &st) == -1)
168 {
9dcee057 169 state = RS_RUNNING;
b50f996d 170 com_err(whoami, 0, "motd gone. reg_svr is running");
171 }
172
173 memcpy(&readfds, &xreadfds, sizeof(readfds));
174 if (select(nfds, &readfds, NULL, NULL, NULL) == -1)
175 {
176 if (errno != EINTR)
177 com_err(whoami, errno, "in select");
178 continue;
179 }
180
181 if (FD_ISSET(listener, &readfds))
182 {
183 int newconn, addrlen = sizeof(struct sockaddr_in);
184 struct sockaddr_in addr;
185
186 newconn = accept(listener, (struct sockaddr *)&addr, &addrlen);
187 if (newconn < 0)
188 com_err(whoami, errno, "accepting new connection");
189 else
190 {
191 nclients++;
192 if (nclients > clientssize)
193 {
194 clientssize = 2 * clientssize;
195 clients = xrealloc(clients, clientssize *
196 sizeof(reg_client));
197 }
198
199 cl = &clients[nclients - 1];
200 memset(cl, 0, sizeof(reg_client));
201 cl->fd = newconn;
202 cl->lastmod = time(NULL);
203 cl->clientid = ++clientid;
204 cl->random = init_rand(cl);
205 FD_SET(newconn, &xreadfds);
206 if (newconn >= nfds)
207 nfds = newconn + 1;
208
209 com_err(whoami, 0,
210 "New connection from %s port %d (now %d client%s)",
211 inet_ntoa(addr.sin_addr), (int)ntohs(addr.sin_port),
212 nclients, nclients != 1 ? "s" : "");
213 }
214 }
215
216 for (i = 0; i < nclients; i++)
217 {
218 cl = &clients[i];
219 if (FD_ISSET(cl->fd, &readfds))
220 {
221 cl->lastmod = time(NULL);
222 if (!cl->buf)
223 {
224 /* We're just starting */
225 cl->buf = malloc(3);
226 if (!cl->buf)
227 {
228 com_err(whoami, errno, "allocating read buffer");
229 reply(cl, INTERNAL_ERROR, "INIT", "c", NULL,
230 "Out of memory");
231 goto reap;
232 }
233 cl->nread = 0;
234 }
235
236 if (cl->nread < 3)
237 {
238 /* We haven't read the length byte yet... */
239 cl->nread += read(cl->fd, cl->buf + cl->nread,
240 3 - cl->nread);
241 if (cl->nread == 3)
242 {
243 cl->nmax = cl->buf[1] * 256 + cl->buf[2] + 3;
244 cl->buf = realloc(cl->buf, cl->nmax + 3);
245 if (!cl->buf)
246 {
247 com_err(whoami, errno, "reallocating read buffer");
248 reply(cl, INTERNAL_ERROR, "INIT", "c", NULL,
249 "Out of memory");
250 goto reap;
251 }
252 }
253 else if (cl->nread == 0)
254 {
255 /* client has closed connection. setting
256 lastmod will cause it to be reaped */
257 cl->lastmod = 0;
258 }
259 }
260 else
261 {
262 /* We know how long the packet is supposed to be */
263 cl->nread += read(cl->fd, cl->buf + cl->nread,
264 cl->nmax - cl->nread);
265 if (cl->nread == cl->nmax)
266 {
267 parse_packet(cl, cl->buf[0], cl->nread - 3, cl->buf + 3,
268 state == RS_SLEEPING);
269 free(cl->buf);
270 cl->buf = NULL;
271 }
272 }
273 }
274
275 reap:
276 if (cl->lastmod < time(NULL) - TIMEOUT)
277 {
278 com_err(whoami, 0, "Closed connection. (now %d client%s)",
279 nclients - 1, nclients != 2 ? "s" : "");
280 shutdown(cl->fd, 2);
281 close(cl->fd);
282 FD_CLR(cl->fd, &xreadfds);
283 free(cl->buf);
284 free(cl->id);
285 free(cl->username);
286 free(cl->suggestions);
287 free(cl->random);
288 clients[i] = clients[--nclients];
289 i--;
290 }
291 }
292 cl = NULL;
293 }
294 com_err(whoami, 0, "Exiting.");
295}
296
297void RIFO(reg_client *rc, int argc, char **argv)
298{
299 EXEC SQL BEGIN DECLARE SECTION;
300 char *ufirst, *umiddle, *ulast, *id;
301 char login[USERS_LOGIN_SIZE], first[USERS_FIRST_SIZE];
302 char middle[USERS_MIDDLE_SIZE], last[USERS_LAST_SIZE];
303 char fullname[USERS_FIRST_SIZE + USERS_MIDDLE_SIZE + USERS_LAST_SIZE];
ee47c73a 304 char class[USERS_TYPE_SIZE], pin[USERS_PIN_SIZE];
1dc2ec48 305 int uid, status, secure, sqlstatus, count;
b50f996d 306 EXEC SQL END DECLARE SECTION;
307
308 if (rc->uid || argc != 4)
309 {
310 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
311 return;
312 }
313
314 ufirst = argv[0];
315 umiddle = argv[1];
316 ulast = argv[2];
317 id = argv[3];
318
1dc2ec48 319 EXEC SQL SELECT count(login) INTO :count FROM users WHERE clearid = :id;
320
b50f996d 321 /* "ORDER BY status" so that if there's both a matching state 0 entry
322 and a matching state 3 entry, we'll get the former. */
323 EXEC SQL DECLARE csr_id CURSOR FOR
ee47c73a 324 SELECT login, unix_uid, status, secure, pin, first, middle, last, type
b50f996d 325 FROM users WHERE clearid = :id ORDER BY status;
326 EXEC SQL OPEN csr_id;
327 while (1)
328 {
329 EXEC SQL FETCH csr_id INTO :login, :uid, :status,
ee47c73a 330 :secure, :pin, :first, :middle, :last, :class;
b50f996d 331 if (sqlca.sqlcode)
332 break;
333 strtrim(login);
334 strtrim(first);
335 strtrim(middle);
336 strtrim(last);
337 strtrim(class);
ee47c73a 338 strtrim(pin);
b50f996d 339
1dc2ec48 340 /* It's possible they have both a deleted account and a status 8
341 * account. We can't compensate for that in the ORDER BY clause
342 * above, so check here. If they have more than one entry and the
343 * first one we get is deleted, skip it.
344 */
345 if (status == US_DELETED && count > 1)
346 continue;
347
b50f996d 348 /* Check names, allowing for the possibility that Moira and the
349 user might have them split up differently. eg, Mary/Ann/Singleton
350 vs. Mary Ann/Singleton. */
351 if (strcasecmp(last, ulast) && strncasecmp(last, ulast, strlen(last)) &&
352 strncasecmp(last, ulast, strlen(ulast)))
353 continue;
354 if (strlen(last) > 3 && strlen(ulast) < 3)
355 continue;
356 if (strcasecmp(first, ufirst) &&
357 strncasecmp(first, ufirst, strlen(first)) &&
358 strncasecmp(first, ufirst, strlen(ufirst)))
359 continue;
360 if (strlen(first) > 3 && strlen(ufirst) < 3)
361 continue;
ba41d432 362 if (!*ufirst && !*ulast)
363 continue;
364
b50f996d 365 /* Ignore the middle name since Moira doesn't have those reliably */
366 break;
367 }
368 sqlstatus = sqlca.sqlcode;
369 EXEC SQL CLOSE csr_id;
370
371 if (sqlstatus)
372 {
373 reply(rc, NOT_FOUND_IN_DATABASE, "GETN", "d", NULL);
374 return;
375 }
376
377 switch (status)
378 {
379 case US_REGISTERED:
380 case US_ENROLLED:
381 case US_ENROLL_NOT_ALLOWED:
9d5ca0f4 382 case US_REGISTERED_KERBEROS_ONLY:
b50f996d 383 reply(rc, ALREADY_REGISTERED, "INIT", "c", NULL, login);
384 return;
385
386 case US_DELETED:
387 reply(rc, ACCOUNT_DELETED, "INIT", "c", NULL, login);
388 return;
389
390 case US_NOT_ALLOWED:
391 reply(rc, NOT_ELIGIBLE, "INIT", "c", NULL);
392 return;
393
394 default:
395 break;
396 }
397
9d5ca0f4 398 rc->user_status = status;
b50f996d 399 rc->uid = uid;
400 sprintf(fullname, "%s %s%s%s", first, middle, *middle ? " " : "", last);
401 if (!strcmp(class, "MITS"))
402 strcpy(class, "STAFF");
403 if (secure == 1)
404 {
405 rc->id = strdup(id);
406 if (!rc->id)
407 {
408 com_err(whoami, errno, "in RIFO");
409 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
410 return;
411 }
412 }
413 if (*login != '#')
414 {
415 rc->reserved_username = 1;
416 rc->username = strdup(login);
417 if (!rc->username)
418 {
419 com_err(whoami, errno, "in RIFO");
420 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
421 return;
422 }
423 }
424 else
425 {
426 rc->suggestions = find_usernames(first, middle, last);
8dc13a24 427 if (!rc->suggestions && errno)
b50f996d 428 {
429 com_err(whoami, errno, "in RIFO");
8dc13a24 430 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(errno));
b50f996d 431 return;
432 }
433 }
434
435 if (rc->id)
ee47c73a 436 {
437 if (*pin != '\0')
438 reply(rc, FOUND, "GETI", "c", NULL, fullname, class);
439 else
440 reply(rc, FOUND, "GETW", "c", NULL, fullname, class);
441 }
b50f996d 442 else if (!rc->username)
443 reply(rc, FOUND, "GETL", "c", rc->suggestions, fullname, class);
444 else
78b14dbc 445 {
9d5ca0f4 446 if (rc->user_status == US_NO_LOGIN_YET ||
447 rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
78b14dbc 448 {
449 status = check_kerberos(login);
9d5ca0f4 450 if (status == MR_SUCCESS &&
451 rc->user_status != US_NO_LOGIN_YET_KERBEROS_ONLY)
452 status = register_user(rc->uid, login);
78b14dbc 453 if (status == MR_IN_USE)
454 {
455 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
456 rc->username);
457 return;
458 }
459 else if (status == MR_DOWN)
460 {
461 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
462 return;
463 }
464 else if (status != MR_SUCCESS)
465 {
466 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL,
467 error_message(status));
468 return;
469 }
470 }
471 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
472 }
b50f996d 473}
474
475void SWRD(reg_client *rc, int argc, char **argv)
476{
477 char *words[6];
478 int i;
479
480 if (!rc->id || argc != 6)
481 {
482 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
483 return;
484 }
485
486 getwordlist(rc->id, words);
487 for (i = 0; i < 6; i++)
488 {
489 if (strcasecmp(strtrim(argv[i]), words[i]))
490 break;
491 }
492 if (i != 6)
493 {
494 reply(rc, BAD_SIX_WORDS, "GETW", "d", NULL);
495 return;
496 }
497
498 free(rc->id);
499 rc->id = NULL;
500 if (!rc->username)
501 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
502 else
503 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
504}
505
ee47c73a 506void SPIN(reg_client *rc, int argc, char **argv)
507{
508 EXEC SQL BEGIN DECLARE SECTION;
509 char pin[USERS_PIN_SIZE];
510 EXEC SQL END DECLARE SECTION;
511
512 if (!rc->id || argc != 1)
513 {
514 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
515 return;
516 }
517
483aa0a7 518 EXEC SQL SELECT pin INTO :pin FROM users WHERE clearid = :rc->id
1dc2ec48 519 AND status = :rc->user_status;
ee47c73a 520 strtrim(pin);
521 if (strcmp(argv[0], pin) != 0)
522 {
523 reply(rc, BAD_PIN, "GETI", "d", NULL);
524 return;
525 }
526
527 free(rc->id);
528 rc->id = NULL;
529 if (!rc->username)
530 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
531 else
d10e2ed1 532 {
533 register_user(rc->uid, rc->username);
534 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
535 }
ee47c73a 536}
537
276949c1 538void CLGN(reg_client *rc, int argc, char **argv)
539{
540 int i;
541 char *login;
542 long status;
543
544 if (!rc->uid || rc->id || rc->username || argc != 1)
545 {
546 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
547 return;
548 }
549
550 login = argv[0];
551
552 /* make sure someone's not trying to overrun reply */
553 if (strlen(login) > 100)
554 {
555 com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
556 rc->lastmod = 0;
557 return;
558 }
559
560 if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
561 (login[0] == '_') || isdigit(login[0]))
562 {
563 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
564 3, USERS_LOGIN_SIZE - 1);
565 return;
566 }
567
568 for (i = 0; i < strlen(login); i++)
569 {
570 if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
571 {
572 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
573 3, USERS_LOGIN_SIZE - 1);
574 return;
575 }
576 }
577
578 status = check_kerberos(login);
579 if (status == MR_SUCCESS)
580 {
581 status = check_username_available(login);
582 if (status == MR_SUCCESS)
583 {
584 reply(rc, USERNAME_AVAILABLE, "LOGC", "c", login, login);
585 return;
586 }
587 }
588
589 if (status == MR_IN_USE)
590 {
591 if (rc->reserved_username)
592 {
593 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
594 rc->username);
595 return;
596 }
597 reply(rc, USERNAME_UNAVAILABLE, "GETL", "c", rc->suggestions);
598 return;
599 }
600 else if (status == MR_DOWN)
601 {
602 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
603 return;
604 }
605 else if (status != MR_SUCCESS)
606 {
607 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(status));
608 return;
609 }
610}
611
b50f996d 612void LOGN(reg_client *rc, int argc, char **argv)
613{
614 int i;
615 char *login;
616 long status;
617
618 if (!rc->uid || rc->id || rc->username || argc != 1)
619 {
620 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
621 return;
622 }
623
624 login = argv[0];
625
626 /* make sure someone's not trying to overrun reply */
627 if (strlen(login) > 100)
628 {
629 com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
630 rc->lastmod = 0;
631 return;
632 }
633
634 if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
635 (login[0] == '_') || isdigit(login[0]))
636 {
637 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
638 3, USERS_LOGIN_SIZE - 1);
639 return;
640 }
641
642 for (i = 0; i < strlen(login); i++)
643 {
644 if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
645 {
646 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
647 3, USERS_LOGIN_SIZE - 1);
648 return;
649 }
650 }
651
652 status = check_kerberos(login);
653 if (status == MR_SUCCESS)
9d5ca0f4 654 {
655 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
656 EXEC SQL UPDATE users SET login = :login WHERE unix_uid = :rc->uid;
657 else
658 status = register_user(rc->uid, login);
659 }
b50f996d 660 if (status == MR_IN_USE)
661 {
662 if (rc->reserved_username)
663 {
664 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
665 rc->username);
666 return;
667 }
668 reply(rc, USERNAME_UNAVAILABLE, "GETL", "c", rc->suggestions);
669 return;
670 }
671 else if (status == MR_DOWN)
672 {
673 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
674 return;
675 }
676 else if (status != MR_SUCCESS)
677 {
678 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(status));
679 return;
680 }
681
682 rc->username = strdup(login);
683 if (!rc->username)
684 {
685 com_err(whoami, errno, "in LOGN");
686 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
687 return;
688 }
689 reply(rc, USERNAME_OK, "GETP", "c", NULL, login);
690}
691
692int ctypes[256] = {
693 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ - ^O */
694 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^P - ^_ */
695 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* SPACE - / */
696 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, /* 0 - ? */
697 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* : - O */
698 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, /* P - _ */
699 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* ` - o */
700 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, /* p - ^? */
701 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
702 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
703 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
704 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
705 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
706 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
707 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
708 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
709};
710
711void PSWD(reg_client *rc, int argc, char **argv)
712{
713 long status;
714 char *password = argv[0], *p;
715 EXEC SQL BEGIN DECLARE SECTION;
716 char *login = rc->username;
717 EXEC SQL END DECLARE SECTION;
718
719 if (!rc->username || rc->id || argc != 1)
720 {
721 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
722 return;
723 }
724
725 /* password quality checking */
726 if (strlen(password) < 4)
727 {
728 reply(rc, PASSWORD_SHORT, "GETP", "c", NULL);
729 return;
730 }
731
732 if (strlen(password) < 7)
733 {
734 for (p = password + 1; *p; p++)
735 {
736 if (ctypes[*p] != ctypes[*(p - 1)])
737 break;
738 }
739 if (!*p)
740 {
741 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
742 return;
743 }
744 }
745
746 if (!strcasecmp(password, "GykoR-66") ||
747 !strcasecmp(password, "slaRooBey") ||
748 !strcasecmp(password, "krang-its") ||
749 !strcasecmp(password, "2HotPeetzas") ||
750 !strcasecmp(password, "ItzAGurl"))
751 {
752 reply(rc, PASSWORD_SAMPLE, "GETP", "c", NULL);
753 return;
754 }
755
756 status = register_kerberos(rc->username, password);
9c0c1480 757 if (status == MR_QUALITY)
758 {
759 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
760 return;
761 }
762 else if (status == MR_IN_USE)
b50f996d 763 {
764 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
765 rc->username);
766 return;
767 }
768 else if (status)
769 {
770 com_err(whoami, status, "registering username with Kerberos");
771 reply(rc, KADM_ERROR, "INIT", "c", NULL, error_message(status));
772 return;
773 }
9d5ca0f4 774
775 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
776 EXEC SQL UPDATE users SET status = 9 WHERE login = :login;
777 else
778 EXEC SQL UPDATE users SET status = 1 WHERE login = :login;
b50f996d 779 EXEC SQL COMMIT;
780
781 reply(rc, DONE, "INIT", "c", NULL, rc->username);
782}
783
784void QUIT(reg_client *rc, int argc, char **argv)
785{
786}
787
788/* Register a user in Moira */
789int register_user(int uid, char *username)
790{
93ab973b 791 EXEC SQL BEGIN DECLARE SECTION;
bc06d5e3 792 char class[USERS_TYPE_SIZE];
93ab973b 793 EXEC SQL END DECLARE SECTION;
b50f996d 794 char uidbuf[10], *qargv[3], *motd = NULL;
795 long status;
796
797 status = mr_connect(hostname);
798 if (status)
799 return status;
800
801 status = mr_motd(&motd);
802 if (status || motd)
803 {
804 mr_disconnect();
805 return MR_DOWN;
806 }
807
808 status = krb_get_svc_in_tkt(REG_SVR_PRINCIPAL, REG_SVR_INSTANCE,
809 krb_realmofhost(hostname), MOIRA_SNAME,
8e2c32b2 810 shorthostname, 3, KEYFILE);
b50f996d 811 if (status)
812 status += ERROR_TABLE_BASE_krb;
813 else
991417e4 814 status = mr_krb5_auth("reg_svr");
b50f996d 815 if (status)
816 {
817 com_err(whoami, status, "authenticating to moira");
818 mr_disconnect();
819 return MR_INTERNAL;
820 }
821
bc06d5e3 822 EXEC SQL SELECT type INTO :class FROM users WHERE unix_uid = :uid;
93ab973b 823
b50f996d 824 sprintf(uidbuf, "%d", uid);
825 qargv[0] = uidbuf;
826 qargv[1] = username;
93ab973b 827
bc06d5e3 828 /* Incoming students should be given Exchange poboxes.
829 * Doesn't work for undergrads in the class of 2100 or higher.
93ab973b 830 */
bc06d5e3 831 if (!strcmp(strtrim(class), "G") || !strncmp(class, "FALL", 4) ||
832 !strncmp(class, "SPRING", 5) || !strncmp(class, "SUMMER", 6) ||
833 !strncmp(class, "20", 2))
834 {
835 com_err(whoami, 0, "assigning EXCHANGE pobox to user %s, class %s", username, class);
93ab973b 836 qargv[2] = "EXCHANGE";
bc06d5e3 837 }
93ab973b 838 else
bc06d5e3 839 {
840 com_err(whoami, 0, "assigning IMAP pobox to user %s, class %s", username, class);
841 qargv[2] = "IMAP";
842 }
93ab973b 843
b50f996d 844 status = mr_query("register_user", 3, qargv, NULL, NULL);
845 mr_disconnect();
846 return status;
847}
848
849
850/* Find some typical available usernames */
851
852char *uname_patterns[] = {
853 "FL", /* johndoe */
854 "fmllllll", /* jmdoe... (last name truncated) */
855 "flllllll", /* jdoe.... ("") */
856 "llllllll", /* doe..... ("") */
857 "fml", /* jmd */
858 "Fl", /* johnd */
859 "Lf", /* doej */
860 "Lfm", /* doejm */
861 "F", /* john */
862};
863int num_patterns = sizeof(uname_patterns) / sizeof(char *);
864
865char *find_usernames(char *first, char *middle, char *last)
866{
867 EXEC SQL BEGIN DECLARE SECTION;
868 char username[2 * USERS_LOGIN_SIZE];
869 int count;
870 EXEC SQL END DECLARE SECTION;
871 int pat, len;
872 char *pp, *up, *fp, *mp, *lp, *unames = NULL;
873
874 fixname(first);
875 fixname(middle);
876 fixname(last);
877
878 for (pat = 0; pat < num_patterns; pat++)
879 {
880 up = username;
881 fp = first;
882 mp = middle;
883 lp = last;
884 for (pp = uname_patterns[pat]; *pp; pp++)
885 {
886 switch (*pp)
887 {
888 case 'f':
889 if (*fp)
890 *up++ = *fp++;
891 break;
892
893 case 'F':
894 if (up - username + strlen(first) < USERS_LOGIN_SIZE)
895 up += sprintf(up, "%s", first);
896 else
897 goto nextpattern;
898 break;
899
900 case 'm':
901 if (!*middle)
902 goto nextpattern;
903 if (*mp)
904 *up++ = *mp++;
905 break;
906
907 case 'l':
908 if (*lp)
909 *up++ = *lp++;
910 break;
911
912 case 'L':
913 if (up - username + strlen(last) < USERS_LOGIN_SIZE)
914 up += sprintf(up, "%s", last);
915 else
916 goto nextpattern;
917 break;
918 }
919 }
920 *up = '\0';
921
d1d04a6c 922 if (strlen(username) < 3 || strlen(username) >= USERS_LOGIN_SIZE)
b50f996d 923 continue;
924
925 EXEC SQL SELECT COUNT(login) INTO :count FROM users
926 WHERE login = :username;
927 if (sqlca.sqlcode)
8dc13a24 928 {
929 errno = MR_DBMS_ERR;
930 return NULL;
931 }
b50f996d 932 if (count == 0)
933 {
934 EXEC SQL SELECT COUNT(name) INTO :count FROM list
935 WHERE name = :username;
936 if (sqlca.sqlcode)
8dc13a24 937 {
938 errno = MR_DBMS_ERR;
939 return NULL;
940 }
b50f996d 941 }
942 if (count == 0)
943 {
944 EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
945 WHERE label = :username;
946 if (sqlca.sqlcode)
8dc13a24 947 {
948 errno = MR_DBMS_ERR;
949 return NULL;
950 }
b50f996d 951 }
952
953 if (count == 0)
954 {
955 if (unames)
956 {
957 unames = realloc(unames, strlen(unames) + strlen(username) + 3);
958 if (!unames)
959 return NULL;
960 strcat(unames, ", ");
961 strcat(unames, username);
962 }
963 else
964 {
965 unames = strdup(username);
966 if (!unames)
967 return NULL;
968 }
969 }
970
971 nextpattern:
972 ;
973 }
974
8dc13a24 975 /* unames will be NULL if we couldn't suggest a username. Clear
976 errno so the caller can distinguish this from an error case. */
977 errno = 0;
b50f996d 978 return unames;
979}
980
276949c1 981/* This does the database-side checks to make sure a username is
982 * available.
983 */
984int check_username_available(char *username)
985{
986 int count;
987
988 EXEC SQL SELECT COUNT(login) INTO :count FROM users
989 WHERE login = :username;
990 if (sqlca.sqlcode)
991 return MR_DBMS_ERR;
992 if (count != 0)
993 return MR_IN_USE;
994
995 EXEC SQL SELECT COUNT(name) INTO :count FROM list
996 WHERE name = :username;
997 if (sqlca.sqlcode)
998 return MR_DBMS_ERR;
999 if (count != 0)
1000 return MR_IN_USE;
1001
1002 EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
1003 WHERE label = :username;
1004 if (sqlca.sqlcode)
1005 return MR_DBMS_ERR;
1006 if (count != 0)
1007 return MR_IN_USE;
1008
1009 return MR_SUCCESS;
1010}
1011
b50f996d 1012void fixname(char *name)
1013{
1014 char *s, *d;
1015
1016 for (s = d = name; *s; s++)
1017 {
1018 if (isalnum(*s))
1019 *d++ = tolower(*s);
1020 }
1021 *d = '\0';
1022}
1023
1024void *xmalloc(size_t bytes)
1025{
1026 void *buf = malloc(bytes);
1027
1028 if (buf)
1029 return buf;
1030
1031 com_err(whoami, errno, "in xmalloc");
1032 exit(1);
1033}
1034
1035void *xrealloc(void *ptr, size_t bytes)
1036{
1037 void *buf = realloc(ptr, bytes);
1038
1039 if (buf)
1040 return buf;
1041
1042 com_err(whoami, errno, "in xrealloc");
1043 exit(1);
1044}
1045
1046char *xstrdup(char *str)
1047{
1048 char *buf = strdup(str);
1049
1050 if (buf)
1051 return buf;
1052
1053 com_err(whoami, errno, "in xstrdup");
1054 exit(1);
1055}
1056
1057void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar)
1058{
1059 if (whoami)
1060 {
1061 fputs(whoami, stderr);
1062 if (cl)
1063 fprintf(stderr, "[#%d]", cl->clientid);
1064 fputs(": ", stderr);
1065 }
1066 if (code) {
1067 fputs(error_message(code), stderr);
1068 fputs(" ", stderr);
1069 }
1070 if (fmt)
1071 vfprintf(stderr, fmt, pvar);
1072 putc('\n', stderr);
1073}
1074
1075void sigshut(int sig)
1076{
1077 state = RS_EXITING;
1078}
This page took 0.502414 seconds and 5 git commands to generate.