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