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