6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
8 * Server for user registration with SMS and Kerberos.
10 * This program is a client of the Kerberos admin_server and a
11 * server for the userreg program. It is not a client of the
12 * SMS server as it is linked with libsmsglue which bypasses
13 * the network protocol.
17 static char *rcsid_reg_svr_c = "$Header$";
23 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
33 #include "ureg_proto.h"
37 #include "admin_server.h"
38 #include "admin_err.h"
48 #define FAIL_INST "reg_svr" /* Instance for failure zephyrgrams */
50 #define CUR_UREG_VERSION 1 /* Version for the register protocol */
51 #define SUCCESS 0 /* General purpose success code */
52 #define FAILURE 1 /* To use when any non-zero number will work */
53 #define min(a,b) ((a)>(b)?(b):(a))
54 #define MIN_UNAME 3 /* Username must be between three and */
55 #define MAX_UNAME 8 /* eight characters long. */
56 #define CRYPT_LEN 14 /* crypt() returns a 13 char string */
57 #define LOGIN_LEN MAX_UNAME + 1 /* Leave room for a null */
58 #define UID_LEN 7 /* Allow room for a 16 bit number */
61 /* This MUST be correct! There isn't a good way of getting this without
62 hardcoding that would not make testing impractical. */
64 extern char *strdup();
65 extern char *malloc();
66 extern int krb_err_base;
67 extern char admin_errmsg[];
69 extern char *whoami; /* Name of program - used by libraries */
70 extern int errno; /* Unix error number */
72 /* This structure holds information from the SMS database that will be
73 worth holding on to. An instance of it appears in the formatted
77 char mit_id[CRYPT_LEN]; /* Encrypted MIT ID */
78 int reg_status; /* Registration status */
79 char uid[UID_LEN]; /* Reserved uid */
80 char login[LOGIN_LEN]; /* Login (username) */
83 /* This structure stores information sent over in the packet in a
84 more convenient format and also stores some information obtained
85 from the database that will be needed for each transaction. It
86 initialized from format_pkt() and find_user(). */
89 U_32BIT version; /* User registration protocol version */
90 U_32BIT request; /* Request */
91 char *first; /* First name */
92 char *last; /* Last name */
93 char *encrypted; /* Encrypted information in packet */
94 int encrypted_len; /* Length of encrypted information in packet */
95 char *leftover; /* Leftover information sent in the packet */
96 int leftover_len; /* Length of leftover information */
97 struct db_data db; /* Information from the SMS database */
100 static char krbhst[BUFSIZ]; /* kerberos server name */
101 static char krbrealm[REALM_SZ]; /* kerberos realm name */
108 struct servent *sp; /* Service info from /etc/services */
109 int s; /* Socket descriptor */
110 struct sockaddr_in sin; /* Internet style socket address */
111 int addrlen; /* Size of socket address (sin) */
112 char packet[BUFSIZ]; /* Buffer for packet transmission */
113 int pktlen; /* Length of packet */
114 U_32BIT seqno; /* Sequence number for packet transmission */
115 struct msg message; /* Storage for parsed packet */
116 int status = SUCCESS; /* Error status */
117 char retval[BUFSIZ]; /* Buffer to hold return message for client */
119 void failure_alert(); /* Log an unexplainable failure */
120 int parse_pkt(); /* Parse a packet from the client */
121 int format_pkt(); /* Prepare a packet to send to client*/
122 int verify_user(); /* Make sure user is allowed to register */
123 int reserve_user(); /* Reserve a login for this user */
124 int set_password(); /* Set this user's password */
128 /* Error messages sent one line at a time */
131 /* Initialize user registration error table for com_err */
134 /* Get service information from /etc/services */
135 if ((sp = getservbyname("sms_ureg", "udp")) == NULL)
137 com_err(whoami, errno, " unknown service sms_ureg/udp");
141 /* Get an internet style datagram socket */
142 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
144 com_err(whoami,errno," socket");
147 bzero((char *)&sin,(int)sizeof(sin));
149 sin.sin_family = AF_INET;
150 sin.sin_port = sp->s_port;
151 sin.sin_addr.s_addr = INADDR_ANY;
153 /* Bind a name to the socket */
154 if (bind(s, &sin, sizeof(sin)) < 0)
156 com_err(whoami,errno," bind");
160 /* Connect to the SMS server */
161 if ((status = sms_connect()) != SMS_SUCCESS)
163 com_err(whoami, status, " on connect");
167 /* Authorize, telling the server who you are */
168 if ((status = sms_auth(whoami)) != SMS_SUCCESS)
170 com_err(whoami, status, " on auth");
174 if (status = get_krbrlm(krbrealm, 1)) {
175 status += krb_err_base;
176 com_err(whoami, status, " fetching kerberos realm");
180 if (status = get_krbhst(krbhst, krbrealm, 1)) {
181 status += krb_err_base;
182 com_err(whoami, status, " fetching kerberos hostname");
186 for (s = krbhst; *s && *s != '.'; s++)
192 /* Use com_err or output to stderr for all log messages. */
194 fprintf(stderr,"*** Debugging messages enabled. ***\n");
197 /* Sit around waiting for requests from the client. */
200 com_err(whoami, 0, "*** Ready for next request ***");
201 addrlen = sizeof(sin);
202 bzero(retval, BUFSIZ);
203 /* Receive a packet */
204 if ((pktlen = recvfrom(s,packet,sizeof(packet),0,&sin,&addrlen)) < 0)
206 com_err(whoami,errno," recvfrom");
207 /* Don't worry if error is interrupted system call. */
208 if (errno == EINTR) continue;
212 /* Parse a request packet */
213 if ((status = parse_pkt(packet, pktlen, &seqno, &message)) != SUCCESS)
215 /* If error, format packet to send back to the client */
216 pktlen = sizeof(packet);
217 (void) format_pkt(packet, &pktlen, seqno, status, (char *)NULL);
218 /* Report the error the the client */
219 (void) sendto(s, packet, pktlen, 0, &sin, addrlen);
224 switch((int)message.request)
226 case UREG_VERIFY_USER:
227 status = verify_user(&message,retval);
229 case UREG_RESERVE_LOGIN:
230 status = reserve_user(&message,retval);
232 case UREG_SET_PASSWORD:
233 status = set_password(&message,retval);
237 status = UREG_UNKNOWN_REQUEST;
238 failure_alert("Unknown request %d from userreg.",
243 /* Report what happened to client */
244 pktlen = sizeof(packet);
245 if (format_pkt(packet, &pktlen, seqno, status, retval))
247 com_err(whoami,0,"Client error message was truncated.");
249 (void) sendto(s, packet, pktlen, 0, &sin, addrlen);
253 /* This is necessary so that this server can know where to put its
257 return("/tmp/tkt_ureg");
260 void failure_alert(msg, args)
261 char *msg; /* Text of message, printf format */
262 /* args = arguments, printf style */
263 /* This routine takes care of logging critical error from userreg
264 in the appropriate way. */
266 critical_alert(FAIL_INST, msg, args);
267 com_err(whoami, 0, msg, args);
270 int format_pkt(packet, pktlenp, seqno, cl_status, message)
271 char *packet; /* Packet buffer */
272 int *pktlenp; /* Pointer to packet size */
273 U_32BIT seqno; /* Sequence number */
274 int cl_status; /* Error status to return to client */
275 char *message; /* Error message to return to client */
276 /* This routine prepares a packet to send back to the client. A
277 non-zero return status means that the client error message was
280 int len; /* Amount of message to send */
281 int status = SUCCESS; /* Return status */
283 /* Convert byte order to network byte order */
284 U_32BIT vers = htonl((U_32BIT)CUR_UREG_VERSION);
285 cl_status = htonl((U_32BIT)cl_status);
286 /* Put current user registration protocol version into the packet */
287 bcopy((char *)&vers, packet, sizeof(U_32BIT));
288 /* Put sequence number into the packet */
289 bcopy((char *)&seqno, packet+sizeof(U_32BIT), sizeof(U_32BIT));
290 /* Put error status into the packet */
291 bcopy((char *)&cl_status, packet+ 2*sizeof(U_32BIT), sizeof(U_32BIT));
293 /* Find out how much of the message to copy; truncate if too short. */
294 /* How much room is there left? */
295 len = *pktlenp - sizeof(U_32BIT)*3;
296 if (len < strlen(message) + 1) /* Room for null terminator */
298 status = FAILURE; /* Message was truncated */
299 /* Truncate the message */
300 message[len-1] = NULL;
303 /* Copy the message into the packet */
304 (void) strcpy(packet+3*sizeof(U_32BIT), message);
305 *pktlenp = 3*sizeof(U_32BIT) + strlen(message);
310 int parse_encrypted(message,data)
311 struct msg *message; /* Formatted packet */
312 struct db_data *data; /* Data from the SMS database */
313 /* This routine makes sure that the ID from the database matches
314 the ID sent accross in the packet. The information in the packet
315 was created in the following way:
317 The plain text ID number was encrypted via EncryptID() resulting
318 in the form that would appear in the SMS database. This is
319 concatinated to the plain text ID so that the ID string contains plain
320 text ID followed by a null followed by the encrypted ID. Other
321 information such as the username or password is appended. The whole
322 thing is then DES encrypted using the encrypted ID as the source of
325 This routine tries each encrypted ID in the database that belongs
326 to someone with this user's first and last name and tries to
327 decrypt the packet with this information. If it succeeds, it returns
328 zero and initializes all the fields of the formatted packet structure
329 that depend on the encrypted information. */
331 C_Block key; /* The key for DES en/decryption */
332 Key_schedule sched; /* En/decryption schedule */
333 static char decrypt[BUFSIZ]; /* Buffer to hold decrypted information */
334 long decrypt_len; /* Length of decypted ID information */
335 char recrypt[14]; /* Buffer to hold re-encrypted information */
336 static char hashid[14]; /* Buffer to hold one-way encrypted ID */
337 char idnumber[BUFSIZ]; /* Buffer to hold plain-text ID */
338 char *temp; /* A temporary string pointer */
339 int len; /* Keeps track of length left in packet */
340 int status = SUCCESS; /* Error status */
343 com_err(whoami,0,"Entering parse_encrypted");
346 /* Make the decrypted information length the same as the encrypted
347 information length. Both are integral multples of eight bytes
348 because of the DES encryption routines. */
349 decrypt_len = (long)message->encrypted_len;
351 /* Get key from the one-way encrypted ID in the SMS database */
352 string_to_key(data->mit_id, key);
353 /* Get schedule from key */
354 key_sched(key, sched);
355 /* Decrypt information from packet using this key. Since decrypt_len
356 is an integral multiple of eight bytes, it will probably be null-
358 pcbc_encrypt(message->encrypted,decrypt, decrypt_len, sched, key, DECRYPT);
360 /* Extract the plain text and encrypted ID fields from the decrypted
361 packet information. */
362 /* Since the decrypted information starts with the plain-text ID
363 followed by a null, if the decryption worked, this will only
364 copy the plain text part of the decrypted information. It is
365 important that strncpy be used because if we are not using the
366 correct key, there is no guarantee that a null will occur
367 anywhere in the string. */
368 (void) strncpy(idnumber,decrypt,(int)decrypt_len);
369 /* Point temp to the end of the plain text ID number. */
370 temp = decrypt + strlen(idnumber) + 1;
371 /* Find out how much more packet there is. */
372 len = message->encrypted_len - (temp - decrypt);
373 /* Copy the next CRYPT_LEN bytes of the decrypted information into
374 hashid if there are CRYPT_LEN more bytes to copy. There will be
375 if we have the right key. */
376 (void) strncpy(hashid, temp, min(len, CRYPT_LEN));
377 /* Point temp to the end of the encrypted ID field */
378 temp += strlen(hashid) + 1;
379 /* Find out how much more room there is. */
380 len = message->encrypted_len - (temp - decrypt);
382 /* Now compare encrypted ID's don't match. */
383 if (strcmp(hashid, data->mit_id)) status = FAILURE;
384 if (status == SUCCESS)
386 EncryptID(recrypt, idnumber, message->first, message->last);
387 /* Now compare encrypted plain text to ID from database. */
388 if (strcmp(recrypt, data->mit_id)) status = FAILURE;
391 if (status == SUCCESS)
393 /* We made it. Now we can finish initializing message. */
394 /* Point leftover to whatever is left over! */
395 message->leftover = temp;
396 message->leftover_len = len;
397 /* Since we know we have the right user, fill in the information
398 from the SMS database. */
399 message->db.reg_status = data->reg_status;
400 (void) strncpy(message->db.uid,data->uid, sizeof(message->db.uid));
401 (void) strncpy(message->db.mit_id,data->mit_id,
402 sizeof(message->db.mit_id));
403 (void) strncpy(message->db.login,data->login, sizeof(message->db.login));
408 com_err(whoami,status," parse_encrypted failed.");
410 com_err(whoami,status,"parse_encrypted succeeded.");
416 int db_callproc(argc,argv,queue)
417 int argc; /* Number of arguments returned by SMS */
418 char *argv[]; /* Arguments returned by SMS */
419 struct save_queue *queue; /* Queue to save information in */
420 /* This function is called by sms_query after each tuple found. It is
421 used by find_user to cache information about each user found. */
423 struct db_data *data; /* Structure to store the information in */
424 int status = SUCCESS; /* Error status */
427 com_err(whoami,0,"Entering db_callproc.");
433 ("Wrong number of arguments returned from get_user_by_name.");
438 /* extract the needed information from the results of the SMS query */
439 data = (struct db_data *)malloc(sizeof(struct db_data));
440 data->reg_status = atoi(argv[U_STATE]);
441 (void) strncpy(data->login,argv[U_NAME],sizeof(data->login));
442 (void) strncpy(data->mit_id,argv[U_MITID],sizeof(data->mit_id));
443 (void) strncpy(data->uid,argv[U_UID],sizeof(data->uid));
445 fprintf(stderr,"Found in database:\n");
446 fprintf(stderr," Registration status: %d\n",data->reg_status);
447 fprintf(stderr," login: %s\n",data->login);
448 fprintf(stderr," MIT ID: %s\n",data->mit_id);
449 fprintf(stderr," uid: %s\n",data->uid);
451 sq_save_data(queue,data);
457 int find_user(message)
458 struct msg *message; /* Formatted packet structure */
459 /* This routine verifies that a user is allowed to register by finding
460 him/her in the SMS database. It returns the status of the SMS
461 query that it calls. */
463 #define GUBN_ARGS 2 /* Arguements needed by get_user_by_name */
464 char *q_name; /* Name of query */
465 int q_argc; /* Number of arguments for query */
466 char *q_argv[GUBN_ARGS]; /* Arguments to query */
467 int status = SUCCESS; /* Query return status */
469 struct save_queue *queue; /* Queue to hold SMS data */
470 struct db_data *data; /* Structure for data for one tuple */
471 short verified = FALSE; /* Have we verified the user? */
473 /* Zero the mit_id field in the formatted packet structure. This
474 being zeroed means that no user was found. */
475 bzero(message->db.mit_id,sizeof(message->db.mit_id));
477 if (status == SUCCESS)
479 /* Get ready to make an SMS query */
480 q_name = "get_user_by_name";
481 q_argc = GUBN_ARGS; /* #defined in this routine */
482 q_argv[0] = message->first;
483 q_argv[1] = message->last;
485 /* Create queue to hold information */
489 status = sms_query(q_name,q_argc,q_argv,db_callproc,(char *)queue);
492 fprintf(stderr," %d returned by get_user_by_name\n",status);
495 if (status == SMS_SUCCESS)
497 /* Traverse the list, freeing data as we go. If sq_get_data()
498 returns zero if there is no more data on the queue. */
499 while (sq_get_data(queue,&data))
502 /* parse_encrypted returns zero on success */
503 verified = (parse_encrypted(message,data) == SUCCESS);
508 /* Destroy the queue */
513 fprintf(stderr,"Returned from find_user\n");
514 fprintf(stderr," MIT ID: %s\n", message->db.mit_id);
515 fprintf(stderr," Registration status: %d\n",message->db.reg_status);
516 fprintf(stderr," uid: %s\n",message->db.uid);
517 fprintf(stderr," login: %s\n",message->db.login);
518 fprintf(stderr," Status from query: %d\n",status);
524 /* The ureg_validate_char variable and routine were taken verbatim
525 out of server/qsupport.qc where they are called
526 validate_chars. At some point, it may be desirable
527 to put this functionality in one place. */
529 /* ureg_validate_char: verify that there are no illegal characters in
530 * the string. Legal characters are printing chars other than
531 * ", *, ?, \, [ and ].
533 static int illegalchars[] = {
534 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
535 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
536 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
537 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
539 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
540 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
541 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
542 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
543 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
544 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
545 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
546 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
547 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
548 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
549 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
552 ureg_validate_char(s)
556 if (illegalchars[*s++])
561 parse_pkt(packet, pktlen, seqnop, message)
566 /* This routine checks a packet and puts the information in it in
567 a structure if it is valid. */
569 int status = SUCCESS; /* Error status */
571 com_err(whoami,0,"Packet received");
573 if (pktlen < sizeof(U_32BIT)) status = UREG_BROKEN_PACKET;
574 if (status == SUCCESS)
576 /* Extract the user registration protocol version from the packet */
577 bcopy(packet, (char *)&message->version, sizeof(long));
578 /* Convert byte order from network to host */
579 message->version = ntohl(message->version);
581 if (message->version != CUR_UREG_VERSION)
582 status = UREG_WRONG_VERSION;
585 if (status == SUCCESS)
587 packet += sizeof(U_32BIT);
588 pktlen -= sizeof(U_32BIT);
590 if (pktlen < sizeof(U_32BIT))
591 status = UREG_BROKEN_PACKET;
594 if (status == SUCCESS)
596 /* Extract the sequence number from the packet */
597 bcopy(packet, (char *)seqnop, sizeof(long));
599 packet += sizeof(U_32BIT);
600 pktlen -= sizeof(U_32BIT);
602 if (pktlen < sizeof(U_32BIT))
603 status = UREG_BROKEN_PACKET;
606 if (status == SUCCESS)
608 /* Extract the request from the packet */
609 bcopy(packet, (char *)(&message->request), sizeof(U_32BIT));
610 message->request = ntohl(message->request);
611 packet += sizeof(U_32BIT);
612 pktlen -= sizeof(U_32BIT);
614 /* Make sure that the packet contains only valid characters up
616 if (ureg_validate_char(packet) != SUCCESS)
618 com_err(whoami,0,"Packet contains invalid characters.");
619 status = UREG_USER_NOT_FOUND;
623 /* Extract first name from the packet */
624 message->first = packet;
626 /* Scan forward until null appears in the packet or there
627 is no more packet! */
628 for (; *packet && pktlen > 0; --pktlen, ++packet) continue;
630 status = UREG_BROKEN_PACKET;
634 if (status == SUCCESS)
636 /* Skip over the null */
639 if (ureg_validate_char(packet) != SUCCESS)
641 com_err(whoami,0,"Packet contains invalid characters.");
642 status = UREG_USER_NOT_FOUND;
646 /* Extract last name from the packet */
647 message->last = packet;
649 for (; *packet && pktlen > 0; --pktlen, ++packet) continue;
651 status = UREG_BROKEN_PACKET;
655 if (status == SUCCESS)
660 status = UREG_BROKEN_PACKET;
663 /* Extract encrypted information from packet */
664 message->encrypted = packet;
665 message->encrypted_len = pktlen;
667 if (status == SUCCESS)
670 com_err(whoami,status,"%s\n%s%d\n%s%d\n%s%s\n%s%s",
671 "Packet parsed successfully. Packet contains:",
672 " Protocol version: ",message->version,
673 " Request: ",message->request,
674 " First name: ",message->first,
675 " Last name: ",message->last);
677 com_err(whoami,status,"Request %d for %s %s",message->request,
678 message->first,message->last);
682 com_err(whoami,status," - parse packet failed.");
687 int verify_user(message,retval)
690 /* This routine determines whether a user is in the databse and returns
691 his state so that other routines can figure out whether he is the
692 correct state for various transactions. */
695 int status = SUCCESS; /* Return status */
697 /* Log that we are about to veryify user */
698 com_err(whoami,0,"verify_user %s %s",message->first,message->last);
700 /* Figure out what user (if any) can be found based on the
701 encrypted information in the packet. (See the comment on
702 parse_encrypted().) */
704 status = find_user(message);
706 /* If SMS coudn't find the user */
707 if (status == SMS_NO_MATCH)
708 status = UREG_USER_NOT_FOUND;
709 else if (status == SMS_SUCCESS)
711 /* If the information sent over in the packet did not point to a
712 valid user, the mit_id field in the formatted packet structure
714 if (message->db.mit_id[0] == NULL)
715 status = UREG_USER_NOT_FOUND;
716 /* If the user was found but the registration has already started,
717 use this as the status */
720 switch (message->db.reg_status)
722 case US_NO_LOGIN_YET:
726 status = UREG_ALREADY_REGISTERED;
729 status = UREG_NO_PASSWD_YET;
732 status = UREG_DELETED;
735 status = UREG_NOT_ALLOWED;
739 status = UREG_MISC_ERROR;
740 failure_alert("Bad user state for %s %s.",
741 message->first,message->last);
744 /* Set retval to the login name so that the client can use
745 it in the error message it will give the user. */
746 (void) strcpy(retval,message->db.login);
750 com_err(whoami,status," returned from verify_user");
757 int status = SUCCESS; /* Return status */
759 /* Get keys for interacting with Kerberos admin server. */
760 /* principal, instance, realm, service, service instance, life, file */
761 if (status = get_svc_in_tkt("register", "sms", krbrealm, "changepw",
763 status += krb_err_base;
766 if (status == SUCCESS)
767 com_err(whoami,status,"Succeeded in getting tickets.");
769 com_err(whoami,status,"Failed to get tickets.");
774 int null_callproc(argc,argv,message)
778 /* This routine is a null callback that should be used for queries that
779 do not return tuples. If it ever gets called, something is wrong. */
781 failure_alert("Something returned from an update query.");
785 int do_admin_call(login, passwd, uid)
786 char *login; /* Requested kerberos principal */
787 char *passwd; /* Requested password */
788 char *uid; /* Uid of user who owns this principal */
789 /* This routine gets tickets, makes the appropriate call to admin_call,
790 and destroys tickets. */
792 int status; /* Error status */
793 char uid_buf[20]; /* Holds uid for kerberos */
795 com_err(whoami,0,"Entering do_admin_call");
797 if ((status = ureg_get_tkt()) == SUCCESS)
799 /* Try to reserve kerberos principal. To do this, send a
800 password request and a null password. It will only succeed
801 if there is no principal or the principal exists and has no
803 /* 13 chars of placebo for backwards-compatability - the admin
804 server protocol reqires this. */
805 bzero(uid_buf,sizeof(uid_buf));
806 (void) sprintf(uid_buf, "%13s", uid);
808 if ((status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, login,
809 "", passwd, uid_buf)) != KSUCCESS)
811 com_err(whoami,status," server error: %s",admin_errmsg);
813 if (strcmp(admin_errmsg,
814 "Principal already in kerberos database.") == 0)
815 status = UREG_KRB_TAKEN;
816 failure_alert("%s is known to Kerberos but not SMS.", login);
821 com_err(whoami,status," returned from do_adin_call");
825 int reserve_user(message,retval)
829 int q_argc; /* Number of arguments to query */
830 char *q_argv[3]; /* Arguments to SMS query */
831 char *q_name; /* Name of SMS query */
832 int status = SUCCESS; /* General purpose error status */
833 char fstype_buf[7]; /* Buffer to hold fs_type, a 16 bit number */
834 char *login; /* The login name the user wants */
835 register int i; /* A counter */
837 /* Log that we are about to reserve a user. */
838 com_err(whoami, 0, "reserve_user %s %s",
839 message->first, message->last);
841 /* Check to make sure that we can verify this user. */
842 if ((status = verify_user(message,retval)) == SUCCESS)
844 /* Get the requested login name from leftover packet information. */
845 login = message->leftover;
847 /* Check the login name for validity. The login name is currently
848 is allowed to contain lowercase letters and numbers in any
849 position and underscore characters and periods in any position
851 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
852 status = UREG_INVALID_UNAME;
854 if (status == SUCCESS)
855 if ((login[0] == '.') || (login[1] == '_'))
856 status = UREG_INVALID_UNAME;
857 if (status == SUCCESS)
859 for (i = 0; i < strlen(login); i++)
860 if (!islower(login[i]) && !isdigit(login[i]) &&
861 (login[i] != '_') && (login[i] != '.'))
863 status = UREG_INVALID_UNAME;
867 if (status == SUCCESS)
869 /* Now that we have a valid user with a valid login... */
871 /* First, try to reserve the user in SMS. */
872 (void) sprintf(fstype_buf,"%d",SMS_FS_STUDENT);
873 q_name = "register_user";
874 q_argv[0] = message->db.uid;
876 q_argv[2] = fstype_buf;
878 status = sms_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
885 status = UREG_LOGIN_USED;
888 status = UREG_MISC_ERROR;
889 failure_alert("%s returned from register_user.",
890 error_message(status));
894 if (status == SUCCESS)
896 /* SMS login was successfully created; try to reserve kerberos
898 /* If this routine fails, store the login in the retval so
899 that it can be used in the client-side error message. */
900 if ((status = do_admin_call(login, "", message->db.uid)) != SUCCESS)
901 (void) strcpy(retval, login);
904 com_err(whoami, status, " returned from reserve_user");
909 int set_final_status(login)
911 /* This routine updates a user's registration status to fully
914 char *q_name; /* Name of SMS query */
915 int q_argc; /* Number of arguments for SMS query */
916 char *q_argv[2]; /* Arguments to get user by uid */
917 char state[7]; /* Can hold a 16 bit integer */
918 int status; /* Error status */
920 com_err(whoami, 0, "Setting final status for %s", login);
922 (void) sprintf(state,"%d",US_REGISTERED);
923 q_name = "update_user_status";
927 if ((status = sms_query(q_name, q_argc, q_argv, null_callproc,
928 (char *)0)) != SMS_SUCCESS)
929 failure_alert("%s returned from update_user_status.",
930 error_message(status));
932 com_err(whoami,status," returned from set_final_status");
937 int set_password(message,retval)
940 /* This routine is used to set the initial password for the new user. */
942 int status = SUCCESS; /* Return status */
943 char *passwd; /* User's password */
945 com_err(whoami, 0, " set_password %s %s",
946 message->first, message->last);
948 status = verify_user(message,retval);
950 /* Don't set the password unless the registration status of the user
951 is that he exists and has no password. */
952 if (status == SUCCESS)
953 status = UREG_NO_LOGIN_YET;
954 if (status == UREG_NO_PASSWD_YET)
956 /* User is in proper state for this transaction. */
958 passwd = message->leftover;
961 if ((status = do_admin_call(message->db.login,
962 passwd, message->db.uid)) != SUCCESS)
963 /* If failure, allow login name to be used in client
965 (void) strcpy(retval,message->db.login);
967 /* Otherwise, mark user as finished. */
968 status = set_final_status(message->db.login);
970 com_err(whoami, status, " returned from set_passwd");
978 * c-argdecl-indent: 2
980 * c-continued-statement-offset: 4