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