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