]> andersk Git - moira.git/blame - reg_svr/reg_svr.pc
Support setting/displaying publicflg for containers, and displaying
[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
520 reply(rc, FORCED_USERNAME, "GETP", "c", NULL, rc->username);
521}
522
b50f996d 523void LOGN(reg_client *rc, int argc, char **argv)
524{
525 int i;
526 char *login;
527 long status;
528
529 if (!rc->uid || rc->id || rc->username || argc != 1)
530 {
531 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
532 return;
533 }
534
535 login = argv[0];
536
537 /* make sure someone's not trying to overrun reply */
538 if (strlen(login) > 100)
539 {
540 com_err(whoami, 0, "Buffer overrun attempted? Closing connection");
541 rc->lastmod = 0;
542 return;
543 }
544
545 if ((strlen(login) < 3) || (strlen(login) > USERS_LOGIN_SIZE - 1) ||
546 (login[0] == '_') || isdigit(login[0]))
547 {
548 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
549 3, USERS_LOGIN_SIZE - 1);
550 return;
551 }
552
553 for (i = 0; i < strlen(login); i++)
554 {
555 if (!islower(login[i]) && !isdigit(login[i]) && (login[i] != '_'))
556 {
557 reply(rc, BAD_USERNAME, "GETL", "c", rc->suggestions, login,
558 3, USERS_LOGIN_SIZE - 1);
559 return;
560 }
561 }
562
563 status = check_kerberos(login);
564 if (status == MR_SUCCESS)
9d5ca0f4 565 {
566 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
567 EXEC SQL UPDATE users SET login = :login WHERE unix_uid = :rc->uid;
568 else
569 status = register_user(rc->uid, login);
570 }
b50f996d 571 if (status == MR_IN_USE)
572 {
573 if (rc->reserved_username)
574 {
575 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
576 rc->username);
577 return;
578 }
579 reply(rc, USERNAME_UNAVAILABLE, "GETL", "c", rc->suggestions);
580 return;
581 }
582 else if (status == MR_DOWN)
583 {
584 reply(rc, DATABASE_CLOSED, "INIT", "c", NULL);
585 return;
586 }
587 else if (status != MR_SUCCESS)
588 {
589 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, error_message(status));
590 return;
591 }
592
593 rc->username = strdup(login);
594 if (!rc->username)
595 {
596 com_err(whoami, errno, "in LOGN");
597 reply(rc, INTERNAL_ERROR, "INIT", "c", NULL, "Out of memory");
598 return;
599 }
600 reply(rc, USERNAME_OK, "GETP", "c", NULL, login);
601}
602
603int ctypes[256] = {
604 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ - ^O */
605 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^P - ^_ */
606 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* SPACE - / */
607 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, /* 0 - ? */
608 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* : - O */
609 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, /* P - _ */
610 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* ` - o */
611 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, /* p - ^? */
612 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
613 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
614 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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};
621
622void PSWD(reg_client *rc, int argc, char **argv)
623{
624 long status;
625 char *password = argv[0], *p;
626 EXEC SQL BEGIN DECLARE SECTION;
627 char *login = rc->username;
628 EXEC SQL END DECLARE SECTION;
629
630 if (!rc->username || rc->id || argc != 1)
631 {
632 reply(rc, PROTOCOL_ERROR, "INIT", "c", NULL);
633 return;
634 }
635
636 /* password quality checking */
637 if (strlen(password) < 4)
638 {
639 reply(rc, PASSWORD_SHORT, "GETP", "c", NULL);
640 return;
641 }
642
643 if (strlen(password) < 7)
644 {
645 for (p = password + 1; *p; p++)
646 {
647 if (ctypes[*p] != ctypes[*(p - 1)])
648 break;
649 }
650 if (!*p)
651 {
652 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
653 return;
654 }
655 }
656
657 if (!strcasecmp(password, "GykoR-66") ||
658 !strcasecmp(password, "slaRooBey") ||
659 !strcasecmp(password, "krang-its") ||
660 !strcasecmp(password, "2HotPeetzas") ||
661 !strcasecmp(password, "ItzAGurl"))
662 {
663 reply(rc, PASSWORD_SAMPLE, "GETP", "c", NULL);
664 return;
665 }
666
667 status = register_kerberos(rc->username, password);
9c0c1480 668 if (status == MR_QUALITY)
669 {
670 reply(rc, PASSWORD_SIMPLE, "GETP", "c", NULL);
671 return;
672 }
673 else if (status == MR_IN_USE)
b50f996d 674 {
675 reply(rc, RESERVED_USERNAME_UNAVAILABLE, "INIT", "c", NULL,
676 rc->username);
677 return;
678 }
679 else if (status)
680 {
681 com_err(whoami, status, "registering username with Kerberos");
682 reply(rc, KADM_ERROR, "INIT", "c", NULL, error_message(status));
683 return;
684 }
9d5ca0f4 685
686 if (rc->user_status == US_NO_LOGIN_YET_KERBEROS_ONLY)
687 EXEC SQL UPDATE users SET status = 9 WHERE login = :login;
688 else
689 EXEC SQL UPDATE users SET status = 1 WHERE login = :login;
b50f996d 690 EXEC SQL COMMIT;
691
692 reply(rc, DONE, "INIT", "c", NULL, rc->username);
693}
694
695void QUIT(reg_client *rc, int argc, char **argv)
696{
697}
698
699/* Register a user in Moira */
700int register_user(int uid, char *username)
701{
702 char uidbuf[10], *qargv[3], *motd = NULL;
703 long status;
704
705 status = mr_connect(hostname);
706 if (status)
707 return status;
708
709 status = mr_motd(&motd);
710 if (status || motd)
711 {
712 mr_disconnect();
713 return MR_DOWN;
714 }
715
716 status = krb_get_svc_in_tkt(REG_SVR_PRINCIPAL, REG_SVR_INSTANCE,
717 krb_realmofhost(hostname), MOIRA_SNAME,
718 shorthostname, 1, KEYFILE);
719 if (status)
720 status += ERROR_TABLE_BASE_krb;
721 else
722 status = mr_auth("reg_svr");
723 if (status)
724 {
725 com_err(whoami, status, "authenticating to moira");
726 mr_disconnect();
727 return MR_INTERNAL;
728 }
729
730 sprintf(uidbuf, "%d", uid);
731 qargv[0] = uidbuf;
732 qargv[1] = username;
4787f97b 733 qargv[2] = "IMAP";
b50f996d 734 status = mr_query("register_user", 3, qargv, NULL, NULL);
735 mr_disconnect();
736 return status;
737}
738
739
740/* Find some typical available usernames */
741
742char *uname_patterns[] = {
743 "FL", /* johndoe */
744 "fmllllll", /* jmdoe... (last name truncated) */
745 "flllllll", /* jdoe.... ("") */
746 "llllllll", /* doe..... ("") */
747 "fml", /* jmd */
748 "Fl", /* johnd */
749 "Lf", /* doej */
750 "Lfm", /* doejm */
751 "F", /* john */
752};
753int num_patterns = sizeof(uname_patterns) / sizeof(char *);
754
755char *find_usernames(char *first, char *middle, char *last)
756{
757 EXEC SQL BEGIN DECLARE SECTION;
758 char username[2 * USERS_LOGIN_SIZE];
759 int count;
760 EXEC SQL END DECLARE SECTION;
761 int pat, len;
762 char *pp, *up, *fp, *mp, *lp, *unames = NULL;
763
764 fixname(first);
765 fixname(middle);
766 fixname(last);
767
768 for (pat = 0; pat < num_patterns; pat++)
769 {
770 up = username;
771 fp = first;
772 mp = middle;
773 lp = last;
774 for (pp = uname_patterns[pat]; *pp; pp++)
775 {
776 switch (*pp)
777 {
778 case 'f':
779 if (*fp)
780 *up++ = *fp++;
781 break;
782
783 case 'F':
784 if (up - username + strlen(first) < USERS_LOGIN_SIZE)
785 up += sprintf(up, "%s", first);
786 else
787 goto nextpattern;
788 break;
789
790 case 'm':
791 if (!*middle)
792 goto nextpattern;
793 if (*mp)
794 *up++ = *mp++;
795 break;
796
797 case 'l':
798 if (*lp)
799 *up++ = *lp++;
800 break;
801
802 case 'L':
803 if (up - username + strlen(last) < USERS_LOGIN_SIZE)
804 up += sprintf(up, "%s", last);
805 else
806 goto nextpattern;
807 break;
808 }
809 }
810 *up = '\0';
811
d1d04a6c 812 if (strlen(username) < 3 || strlen(username) >= USERS_LOGIN_SIZE)
b50f996d 813 continue;
814
815 EXEC SQL SELECT COUNT(login) INTO :count FROM users
816 WHERE login = :username;
817 if (sqlca.sqlcode)
8dc13a24 818 {
819 errno = MR_DBMS_ERR;
820 return NULL;
821 }
b50f996d 822 if (count == 0)
823 {
824 EXEC SQL SELECT COUNT(name) INTO :count FROM list
825 WHERE name = :username;
826 if (sqlca.sqlcode)
8dc13a24 827 {
828 errno = MR_DBMS_ERR;
829 return NULL;
830 }
b50f996d 831 }
832 if (count == 0)
833 {
834 EXEC SQL SELECT COUNT(label) INTO :count FROM filesys
835 WHERE label = :username;
836 if (sqlca.sqlcode)
8dc13a24 837 {
838 errno = MR_DBMS_ERR;
839 return NULL;
840 }
b50f996d 841 }
842
843 if (count == 0)
844 {
845 if (unames)
846 {
847 unames = realloc(unames, strlen(unames) + strlen(username) + 3);
848 if (!unames)
849 return NULL;
850 strcat(unames, ", ");
851 strcat(unames, username);
852 }
853 else
854 {
855 unames = strdup(username);
856 if (!unames)
857 return NULL;
858 }
859 }
860
861 nextpattern:
862 ;
863 }
864
8dc13a24 865 /* unames will be NULL if we couldn't suggest a username. Clear
866 errno so the caller can distinguish this from an error case. */
867 errno = 0;
b50f996d 868 return unames;
869}
870
871void fixname(char *name)
872{
873 char *s, *d;
874
875 for (s = d = name; *s; s++)
876 {
877 if (isalnum(*s))
878 *d++ = tolower(*s);
879 }
880 *d = '\0';
881}
882
883void *xmalloc(size_t bytes)
884{
885 void *buf = malloc(bytes);
886
887 if (buf)
888 return buf;
889
890 com_err(whoami, errno, "in xmalloc");
891 exit(1);
892}
893
894void *xrealloc(void *ptr, size_t bytes)
895{
896 void *buf = realloc(ptr, bytes);
897
898 if (buf)
899 return buf;
900
901 com_err(whoami, errno, "in xrealloc");
902 exit(1);
903}
904
905char *xstrdup(char *str)
906{
907 char *buf = strdup(str);
908
909 if (buf)
910 return buf;
911
912 com_err(whoami, errno, "in xstrdup");
913 exit(1);
914}
915
916void mr_com_err(const char *whoami, long code, const char *fmt, va_list pvar)
917{
918 if (whoami)
919 {
920 fputs(whoami, stderr);
921 if (cl)
922 fprintf(stderr, "[#%d]", cl->clientid);
923 fputs(": ", stderr);
924 }
925 if (code) {
926 fputs(error_message(code), stderr);
927 fputs(" ", stderr);
928 }
929 if (fmt)
930 vfprintf(stderr, fmt, pvar);
931 putc('\n', stderr);
932}
933
934void sigshut(int sig)
935{
936 state = RS_EXITING;
937}
This page took 1.656716 seconds and 5 git commands to generate.