]> andersk Git - moira.git/blame - reg_svr/reg_svr.pc
From dtanner, to deal with more recent Windows.
[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];
9d5ca0f4 304 int uid, status, secure, sqlstatus;
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
318 /* "ORDER BY status" so that if there's both a matching state 0 entry
319 and a matching state 3 entry, we'll get the former. */
320 EXEC SQL DECLARE csr_id CURSOR FOR
ee47c73a 321 SELECT login, unix_uid, status, secure, pin, first, middle, last, type
b50f996d 322 FROM users WHERE clearid = :id ORDER BY status;
323 EXEC SQL OPEN csr_id;
324 while (1)
325 {
326 EXEC SQL FETCH csr_id INTO :login, :uid, :status,
ee47c73a 327 :secure, :pin, :first, :middle, :last, :class;
b50f996d 328 if (sqlca.sqlcode)
329 break;
330 strtrim(login);
331 strtrim(first);
332 strtrim(middle);
333 strtrim(last);
334 strtrim(class);
ee47c73a 335 strtrim(pin);
b50f996d 336
337 /* Check names, allowing for the possibility that Moira and the
338 user might have them split up differently. eg, Mary/Ann/Singleton
339 vs. Mary Ann/Singleton. */
340 if (strcasecmp(last, ulast) && strncasecmp(last, ulast, strlen(last)) &&
341 strncasecmp(last, ulast, strlen(ulast)))
342 continue;
343 if (strlen(last) > 3 && strlen(ulast) < 3)
344 continue;
345 if (strcasecmp(first, ufirst) &&
346 strncasecmp(first, ufirst, strlen(first)) &&
347 strncasecmp(first, ufirst, strlen(ufirst)))
348 continue;
349 if (strlen(first) > 3 && strlen(ufirst) < 3)
350 continue;
351 /* Ignore the middle name since Moira doesn't have those reliably */
352 break;
353 }
354 sqlstatus = sqlca.sqlcode;
355 EXEC SQL CLOSE csr_id;
356
357 if (sqlstatus)
358 {
359 reply(rc, NOT_FOUND_IN_DATABASE, "GETN", "d", NULL);
360 return;
361 }
362
363 switch (status)
364 {
365 case US_REGISTERED:
366 case US_ENROLLED:
367 case US_ENROLL_NOT_ALLOWED:
9d5ca0f4 368 case US_REGISTERED_KERBEROS_ONLY:
b50f996d 369 reply(rc, ALREADY_REGISTERED, "INIT", "c", NULL, login);
370 return;
371
372 case US_DELETED:
373 reply(rc, ACCOUNT_DELETED, "INIT", "c", NULL, login);
374 return;
375
376 case US_NOT_ALLOWED:
377 reply(rc, NOT_ELIGIBLE, "INIT", "c", NULL);
378 return;
379
380 default:
381 break;
382 }
383
9d5ca0f4 384 rc->user_status = status;
b50f996d 385 rc->uid = uid;
386 sprintf(fullname, "%s %s%s%s", first, middle, *middle ? " " : "", last);
387 if (!strcmp(class, "MITS"))
388 strcpy(class, "STAFF");
389 if (secure == 1)
390 {
391 rc->id = strdup(id);
392 if (!rc->id)
393 {
394 com_err(whoami, errno, "in RIFO");
395 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
396 return;
397 }
398 }
399 if (*login != '#')
400 {
401 rc->reserved_username = 1;
402 rc->username = strdup(login);
403 if (!rc->username)
404 {
405 com_err(whoami, errno, "in RIFO");
406 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
407 return;
408 }
409 }
410 else
411 {
412 rc->suggestions = find_usernames(first, middle, last);
8dc13a24 413 if (!rc->suggestions && errno)
b50f996d 414 {
415 com_err(whoami, errno, "in RIFO");
8dc13a24 416 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(errno));
b50f996d 417 return;
418 }
419 }
420
421 if (rc->id)
ee47c73a 422 {
423 if (*pin != '\0')
424 reply(rc, FOUND, "GETI", "c", NULL, fullname, class);
425 else
426 reply(rc, FOUND, "GETW", "c", NULL, fullname, class);
427 }
b50f996d 428 else if (!rc->username)
429 reply(rc, FOUND, "GETL", "c", rc->suggestions, fullname, class);
430 else
78b14dbc 431 {
9d5ca0f4 432 if (rc->user_status == US_NO_LOGIN_YET ||
433 rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
78b14dbc 434 {
435 status = check_kerberos(login);
9d5ca0f4 436 if (status == MR_SUCCESS &&
437 rc->user_status != US_NO_LOGIN_YET_KERBEROS_ONLY)
438 status = register_user(rc->uid, login);
78b14dbc 439 if (status == MR_IN_USE)
440 {
441 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
442 rc->username);
443 return;
444 }
445 else if (status == MR_DOWN)
446 {
447 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
448 return;
449 }
450 else if (status != MR_SUCCESS)
451 {
452 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL,
453 error_message(status));
454 return;
455 }
456 }
457 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
458 }
b50f996d 459}
460
461void SWRD(reg_client *rc, int argc, char **argv)
462{
463 char *words[6];
464 int i;
465
466 if (!rc->id || argc != 6)
467 {
468 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
469 return;
470 }
471
472 getwordlist(rc->id, words);
473 for (i = 0; i < 6; i++)
474 {
475 if (strcasecmp(strtrim(argv[i]), words[i]))
476 break;
477 }
478 if (i != 6)
479 {
480 reply(rc, BAD_SIX_WORDS, "GETW", "d", NULL);
481 return;
482 }
483
484 free(rc->id);
485 rc->id = NULL;
486 if (!rc->username)
487 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
488 else
489 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
490}
491
ee47c73a 492void SPIN(reg_client *rc, int argc, char **argv)
493{
494 EXEC SQL BEGIN DECLARE SECTION;
495 char pin[USERS_PIN_SIZE];
496 EXEC SQL END DECLARE SECTION;
497
498 if (!rc->id || argc != 1)
499 {
500 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
501 return;
502 }
503
ee492c59 504 /* "ORDER BY status" so that if there's both a matching state 0 entry
505 and a matching state 3 entry, we'll get the former. */
483aa0a7 506 EXEC SQL SELECT pin INTO :pin FROM users WHERE clearid = :rc->id
507 ORDER BY status;
ee47c73a 508 strtrim(pin);
509 if (strcmp(argv[0], pin) != 0)
510 {
511 reply(rc, BAD_PIN, "GETI", "d", NULL);
512 return;
513 }
514
515 free(rc->id);
516 rc->id = NULL;
517 if (!rc->username)
518 reply(rc, NO_MESSAGE, "GETL", "c", rc->suggestions);
519 else
d10e2ed1 520 {
521 register_user(rc->uid, rc->username);
522 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
523 }
ee47c73a 524}
525
b50f996d 526void LOGN(reg_client *rc, int argc, char **argv)
527{
528 int i;
529 char *login;
530 long status;
531
532 if (!rc->uid || rc->id || rc->username || argc != 1)
533 {
534 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
535 return;
536 }
537
538 login = argv[0];
539
540 /* make sure someone's not trying to overrun reply */
541 if (strlen(login) > 100)
542 {
543 com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
544 rc->lastmod = 0;
545 return;
546 }
547
548 if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
549 (login[0] == '_') || isdigit(login[0]))
550 {
551 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
552 3, USERS_LOGIN_SIZE - 1);
553 return;
554 }
555
556 for (i = 0; i < strlen(login); i++)
557 {
558 if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
559 {
560 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
561 3, USERS_LOGIN_SIZE - 1);
562 return;
563 }
564 }
565
566 status = check_kerberos(login);
567 if (status == MR_SUCCESS)
9d5ca0f4 568 {
569 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
570 EXEC SQL UPDATE users SET login = :login WHERE unix_uid = :rc->uid;
571 else
572 status = register_user(rc->uid, login);
573 }
b50f996d 574 if (status == MR_IN_USE)
575 {
576 if (rc->reserved_username)
577 {
578 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
579 rc->username);
580 return;
581 }
582 reply(rc, USERNAME_UNAVAILABLE, "GETL", "c", rc->suggestions);
583 return;
584 }
585 else if (status == MR_DOWN)
586 {
587 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
588 return;
589 }
590 else if (status != MR_SUCCESS)
591 {
592 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(status));
593 return;
594 }
595
596 rc->username = strdup(login);
597 if (!rc->username)
598 {
599 com_err(whoami, errno, "in LOGN");
600 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
601 return;
602 }
603 reply(rc, USERNAME_OK, "GETP", "c", NULL, login);
604}
605
606int ctypes[256] = {
607 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ - ^O */
608 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^P - ^_ */
609 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* SPACE - / */
610 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, /* 0 - ? */
611 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* : - O */
612 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, /* P - _ */
613 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* ` - o */
614 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, /* p - ^? */
615 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
616 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
617 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
618 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
619 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
620 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
621 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
622 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
623};
624
625void PSWD(reg_client *rc, int argc, char **argv)
626{
627 long status;
628 char *password = argv[0], *p;
629 EXEC SQL BEGIN DECLARE SECTION;
630 char *login = rc->username;
631 EXEC SQL END DECLARE SECTION;
632
633 if (!rc->username || rc->id || argc != 1)
634 {
635 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
636 return;
637 }
638
639 /* password quality checking */
640 if (strlen(password) < 4)
641 {
642 reply(rc, PASSWORD_SHORT, "GETP", "c", NULL);
643 return;
644 }
645
646 if (strlen(password) < 7)
647 {
648 for (p = password + 1; *p; p++)
649 {
650 if (ctypes[*p] != ctypes[*(p - 1)])
651 break;
652 }
653 if (!*p)
654 {
655 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
656 return;
657 }
658 }
659
660 if (!strcasecmp(password, "GykoR-66") ||
661 !strcasecmp(password, "slaRooBey") ||
662 !strcasecmp(password, "krang-its") ||
663 !strcasecmp(password, "2HotPeetzas") ||
664 !strcasecmp(password, "ItzAGurl"))
665 {
666 reply(rc, PASSWORD_SAMPLE, "GETP", "c", NULL);
667 return;
668 }
669
670 status = register_kerberos(rc->username, password);
9c0c1480 671 if (status == MR_QUALITY)
672 {
673 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
674 return;
675 }
676 else if (status == MR_IN_USE)
b50f996d 677 {
678 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
679 rc->username);
680 return;
681 }
682 else if (status)
683 {
684 com_err(whoami, status, "registering username with Kerberos");
685 reply(rc, KADM_ERROR, "INIT", "c", NULL, error_message(status));
686 return;
687 }
9d5ca0f4 688
689 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
690 EXEC SQL UPDATE users SET status = 9 WHERE login = :login;
691 else
692 EXEC SQL UPDATE users SET status = 1 WHERE login = :login;
b50f996d 693 EXEC SQL COMMIT;
694
695 reply(rc, DONE, "INIT", "c", NULL, rc->username);
696}
697
698void QUIT(reg_client *rc, int argc, char **argv)
699{
700}
701
702/* Register a user in Moira */
703int register_user(int uid, char *username)
704{
705 char uidbuf[10], *qargv[3], *motd = NULL;
706 long status;
707
708 status = mr_connect(hostname);
709 if (status)
710 return status;
711
712 status = mr_motd(&motd);
713 if (status || motd)
714 {
715 mr_disconnect();
716 return MR_DOWN;
717 }
718
719 status = krb_get_svc_in_tkt(REG_SVR_PRINCIPAL, REG_SVR_INSTANCE,
720 krb_realmofhost(hostname), MOIRA_SNAME,
721 shorthostname, 1, KEYFILE);
722 if (status)
723 status += ERROR_TABLE_BASE_krb;
724 else
725 status = mr_auth("reg_svr");
726 if (status)
727 {
728 com_err(whoami, status, "authenticating to moira");
729 mr_disconnect();
730 return MR_INTERNAL;
731 }
732
733 sprintf(uidbuf, "%d", uid);
734 qargv[0] = uidbuf;
735 qargv[1] = username;
4787f97b 736 qargv[2] = "IMAP";
b50f996d 737 status = mr_query("register_user", 3, qargv, NULL, NULL);
738 mr_disconnect();
739 return status;
740}
741
742
743/* Find some typical available usernames */
744
745char *uname_patterns[] = {
746 "FL", /* johndoe */
747 "fmllllll", /* jmdoe... (last name truncated) */
748 "flllllll", /* jdoe.... ("") */
749 "llllllll", /* doe..... ("") */
750 "fml", /* jmd */
751 "Fl", /* johnd */
752 "Lf", /* doej */
753 "Lfm", /* doejm */
754 "F", /* john */
755};
756int num_patterns = sizeof(uname_patterns) / sizeof(char *);
757
758char *find_usernames(char *first, char *middle, char *last)
759{
760 EXEC SQL BEGIN DECLARE SECTION;
761 char username[2 * USERS_LOGIN_SIZE];
762 int count;
763 EXEC SQL END DECLARE SECTION;
764 int pat, len;
765 char *pp, *up, *fp, *mp, *lp, *unames = NULL;
766
767 fixname(first);
768 fixname(middle);
769 fixname(last);
770
771 for (pat = 0; pat < num_patterns; pat++)
772 {
773 up = username;
774 fp = first;
775 mp = middle;
776 lp = last;
777 for (pp = uname_patterns[pat]; *pp; pp++)
778 {
779 switch (*pp)
780 {
781 case 'f':
782 if (*fp)
783 *up++ = *fp++;
784 break;
785
786 case 'F':
787 if (up - username + strlen(first) < USERS_LOGIN_SIZE)
788 up += sprintf(up, "%s", first);
789 else
790 goto nextpattern;
791 break;
792
793 case 'm':
794 if (!*middle)
795 goto nextpattern;
796 if (*mp)
797 *up++ = *mp++;
798 break;
799
800 case 'l':
801 if (*lp)
802 *up++ = *lp++;
803 break;
804
805 case 'L':
806 if (up - username + strlen(last) < USERS_LOGIN_SIZE)
807 up += sprintf(up, "%s", last);
808 else
809 goto nextpattern;
810 break;
811 }
812 }
813 *up = '\0';
814
d1d04a6c 815 if (strlen(username) < 3 || strlen(username) >= USERS_LOGIN_SIZE)
b50f996d 816 continue;
817
818 EXEC SQL SELECT COUNT(login) INTO :count FROM users
819 WHERE login = :username;
820 if (sqlca.sqlcode)
8dc13a24 821 {
822 errno = MR_DBMS_ERR;
823 return NULL;
824 }
b50f996d 825 if (count == 0)
826 {
827 EXEC SQL SELECT COUNT(name) INTO :count FROM list
828 WHERE name = :username;
829 if (sqlca.sqlcode)
8dc13a24 830 {
831 errno = MR_DBMS_ERR;
832 return NULL;
833 }
b50f996d 834 }
835 if (count == 0)
836 {
837 EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
838 WHERE label = :username;
839 if (sqlca.sqlcode)
8dc13a24 840 {
841 errno = MR_DBMS_ERR;
842 return NULL;
843 }
b50f996d 844 }
845
846 if (count == 0)
847 {
848 if (unames)
849 {
850 unames = realloc(unames, strlen(unames) + strlen(username) + 3);
851 if (!unames)
852 return NULL;
853 strcat(unames, ", ");
854 strcat(unames, username);
855 }
856 else
857 {
858 unames = strdup(username);
859 if (!unames)
860 return NULL;
861 }
862 }
863
864 nextpattern:
865 ;
866 }
867
8dc13a24 868 /* unames will be NULL if we couldn't suggest a username. Clear
869 errno so the caller can distinguish this from an error case. */
870 errno = 0;
b50f996d 871 return unames;
872}
873
874void fixname(char *name)
875{
876 char *s, *d;
877
878 for (s = d = name; *s; s++)
879 {
880 if (isalnum(*s))
881 *d++ = tolower(*s);
882 }
883 *d = '\0';
884}
885
886void *xmalloc(size_t bytes)
887{
888 void *buf = malloc(bytes);
889
890 if (buf)
891 return buf;
892
893 com_err(whoami, errno, "in xmalloc");
894 exit(1);
895}
896
897void *xrealloc(void *ptr, size_t bytes)
898{
899 void *buf = realloc(ptr, bytes);
900
901 if (buf)
902 return buf;
903
904 com_err(whoami, errno, "in xrealloc");
905 exit(1);
906}
907
908char *xstrdup(char *str)
909{
910 char *buf = strdup(str);
911
912 if (buf)
913 return buf;
914
915 com_err(whoami, errno, "in xstrdup");
916 exit(1);
917}
918
919void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar)
920{
921 if (whoami)
922 {
923 fputs(whoami, stderr);
924 if (cl)
925 fprintf(stderr, "[#%d]", cl->clientid);
926 fputs(": ", stderr);
927 }
928 if (code) {
929 fputs(error_message(code), stderr);
930 fputs(" ", stderr);
931 }
932 if (fmt)
933 vfprintf(stderr, fmt, pvar);
934 putc('\n', stderr);
935}
936
937void sigshut(int sig)
938{
939 state = RS_EXITING;
940}
This page took 0.18173 seconds and 5 git commands to generate.