/* $Id$ * * Staff/Student load common code * * Copyright (C) 1999 by the Massachusetts Institute of Technology * For copying and distribution information, please see the file * . */ #include #include #include #include #include "common.h" #include #include EXEC SQL INCLUDE sqlca; extern void sqlglm(char *, unsigned int *, unsigned int *); RCSID("$Header$"); EXEC SQL BEGIN DECLARE SECTION; extern char *prog; extern int who; EXEC SQL END DECLARE SECTION; extern char *whoami; #define MIN_ID_VALUE 100 #define MAX_ID_VALUE 131072 /* Remove non-digits from a phone number. */ void fixphone(char *phone) { char *d = phone; while (*phone) { if (isdigit(*phone)) *d++ = *phone; phone++; } *d = '\0'; } /* Remove characters from address that aren't safe for passwd files. */ void fixaddress(char *address) { char *p; while ((p = strchr(address, ','))) *p = ';'; while ((p = strchr(address, ':'))) *p = ';'; } void process_entry(struct entry *e, int secure) { int changed; char buf[MAX_FIELD_WIDTH], *from, *to; EXEC SQL BEGIN DECLARE SECTION; char *first, *last, *middle, *sid; char *name = e->name, *xtitle = e->xtitle, *xaddr = e->xaddress; char *xphone1 = e->xphone1, *xphone2 = e->xphone2; char type[USERS_TYPE_SIZE], oaddr[USERS_OFFICE_ADDR_SIZE]; char ophone[USERS_OFFICE_PHONE_SIZE], dept[USERS_DEPARTMENT_SIZE]; char haddr[USERS_HOME_ADDR_SIZE], hphone[USERS_HOME_PHONE_SIZE]; char dfirst[USERS_FIRST_SIZE], dlast[USERS_LAST_SIZE]; char dmiddle[USERS_MIDDLE_SIZE]; int id, status, fmodby, xnlen = USERS_XNAME_SIZE - 1; EXEC SQL END DECLARE SECTION; sid = e->id; last = e->last; if (strlen(last) > USERS_LAST_SIZE - 1) last[USERS_LAST_SIZE - 1] = '\0'; first = e->first; if (strlen(first) > USERS_FIRST_SIZE - 1) first[USERS_FIRST_SIZE - 1] = '\0'; middle = e->middle; if (strlen(middle) > USERS_MIDDLE_SIZE - 1) middle[USERS_MIDDLE_SIZE - 1] = '\0'; id = 0; /* Get user info */ EXEC SQL SELECT users_id, first, last, middle, type, office_addr, office_phone, home_addr, home_phone, department, status, fmodby INTO :id, :dfirst, :dlast, :dmiddle, :type, :oaddr, :ophone, :haddr, :hphone, :dept, :status, :fmodby FROM users WHERE clearid = :sid AND status != 3; if (sqlfail()) { if (sqlca.sqlcode == SQL_DUPLICATE) { com_err(whoami, 0, "duplicate ID number %s on user %s %s", sid, first, last); return; } else sqlexit(); } if (id == 0) { newuser(e, secure); return; } strtrim(dfirst); strtrim(dlast); strtrim(dmiddle); strtrim(type); /* Update type/state if necessary. (Exclude several spacial cases.) */ if (strcmp(e->type, type) && strcmp(type, "STAFF") && strcmp(type, "SIPBMEM") && strcmp(type, "KNIGHT")) { com_err(whoami, 0, "updating type for %s %s from \"%s\" to \"%s\"", first, last, type, e->type); if (status == US_NOT_ALLOWED) status = US_NO_LOGIN_YET; else if (status == US_ENROLL_NOT_ALLOWED) status = US_ENROLLED; strcpy(type, e->type); EXEC SQL UPDATE users SET type = NVL(:type, CHR(0)), status = :status, modtime = SYSDATE, modby = :who, modwith = :prog WHERE users_id = :id; if (sqlca.sqlcode) { dbmserr("updating user", sqlca.sqlcode); exit(1); } } /* Update name if necessary */ if (strcmp(first, dfirst) || strcmp(last, dlast) || strcmp(middle, dmiddle)) { com_err(whoami, 0, "updating real name for %s%s%s %s (was %s%s%s %s)", first, *middle ? " " : "", middle, last, dfirst, *dmiddle ? " " : "", dmiddle, dlast); EXEC SQL UPDATE users SET first = NVL(:first, CHR(0)), last = NVL(:last, CHR(0)), middle = NVL(:middle, CHR(0)), modby = :who, modwith = :prog, modtime = SYSDATE WHERE users_id = :id; if (sqlca.sqlcode) { dbmserr("updating name", sqlca.sqlcode); exit(1); } } /* Update finger info fields if they have changed and the user * didn't set them blank. */ changed = 0; if (strncmp(strtrim(oaddr), e->oaddr, USERS_OFFICE_ADDR_SIZE - 1) && (*oaddr || fmodby != id)) { changed++; com_err(whoami, 0, "office for %s %s changed from \"%s\" to \"%s\"", first, last, oaddr, e->oaddr); strlcpy(oaddr, e->oaddr, USERS_OFFICE_ADDR_SIZE); } if (strncmp(strtrim(ophone), e->ophone, USERS_OFFICE_PHONE_SIZE - 1) && (*ophone || fmodby != id)) { changed++; com_err(whoami, 0, "Phone for %s %s changed from \"%s\" to \"%s\"", first, last, ophone, e->ophone); strlcpy(ophone, e->ophone, USERS_OFFICE_PHONE_SIZE); } if (strncmp(strtrim(haddr), e->haddr, USERS_HOME_ADDR_SIZE - 1) && (*haddr || fmodby != id)) { changed++; com_err(whoami, 0, "home addr for %s %s changed from \"%s\" to \"%s\"", first, last, haddr, e->haddr); strlcpy(haddr, e->haddr, USERS_HOME_ADDR_SIZE); } if (strncmp(strtrim(hphone), e->hphone, USERS_HOME_PHONE_SIZE - 1) && (*hphone || fmodby != id)) { changed++; com_err(whoami, 0, "Phone for %s %s changed from \"%s\" to \"%s\"", first, last, hphone, e->hphone); strlcpy(hphone, e->hphone, USERS_HOME_PHONE_SIZE); } if (strncmp(strtrim(dept), e->dept, USERS_DEPARTMENT_SIZE - 1) && (*dept || fmodby != id)) { changed++; com_err(whoami, 0, "Department for %s %s changed from \"%s\" to \"%s\"", first, last, dept, e->dept); strlcpy(dept, e->dept, USERS_DEPARTMENT_SIZE); } if (changed) { com_err(whoami, 0, "updating finger for %s %s", first, last); EXEC SQL UPDATE users SET office_addr = NVL(:oaddr, CHR(0)), office_phone = NVL(:ophone, CHR(0)), home_addr = NVL(:haddr, CHR(0)), home_phone = NVL(:hphone, CHR(0)), department = NVL(:dept, CHR(0)), fmodtime = SYSDATE, fmodby = :who, fmodwith = :prog, xname = NVL(SUBSTR(:name, 0, :xnlen), CHR(0)), xdept = NVL(:dept, CHR(0)), xtitle = NVL(:xtitle, CHR(0)), xaddress = NVL(:xaddr, CHR(0)), xphone1 = NVL(:xphone1, CHR(0)), xphone2 = NVL(:xphone2, CHR(0)), xmodtime = SYSDATE WHERE users_id = :id; if (sqlca.sqlcode) { dbmserr(NULL, sqlca.sqlcode); exit(1); } } else { EXEC SQL UPDATE users SET xname = NVL(SUBSTR(:name, 0, :xnlen), CHR(0)), xdept = NVL(:dept, CHR(0)), xtitle = NVL(:xtitle, CHR(0)), xaddress = NVL(:xaddr, CHR(0)), xphone1 = NVL(:xphone1, CHR(0)), xphone2 = NVL(:xphone2, CHR(0)), xmodtime = SYSDATE WHERE users_id = :id; if (sqlca.sqlcode) { dbmserr(NULL, sqlca.sqlcode); exit(1); } } } void newuser(struct entry *e, int secure) { EXEC SQL BEGIN DECLARE SECTION; int issecure = secure, users_id, uid, st, xnlen = USERS_XNAME_SIZE - 1; int oadlen = USERS_OFFICE_ADDR_SIZE - 1; int ophlen = USERS_OFFICE_PHONE_SIZE - 1; char login[USERS_LOGIN_SIZE]; char *id, *last, *first, *middle, *type; char *name, *dept, *haddr, *hphone, *oaddr, *ophone; char *xtitle, *xaddress, *xphone1, *xphone2; EXEC SQL END DECLARE SECTION; users_id = set_next_users_id(); uid = set_next_uid(); sprintf(login, "#%d", uid); if (!strcmp(e->type, "LINCOLN")) st = US_NO_LOGIN_YET_KERBEROS_ONLY; else st = US_NO_LOGIN_YET; last = e->last; first = e->first; middle = e->middle; id = e->id; type = e->type; name = e->name; dept = e->dept; haddr = e->haddr; hphone = e->hphone; oaddr = e->oaddr; ophone = e->ophone; xtitle = e->xtitle; xaddress = e->xaddress; xphone1 = e->xphone1; xphone2 = e->xphone2; com_err(whoami, 0, "adding user %s %s", e->first, e->last); EXEC SQL INSERT INTO users (login, users_id, unix_uid, shell, winconsoleshell, last, first, middle, status, clearid, type, modtime, modby, modwith, fullname, department, home_addr, home_phone, office_addr, office_phone, fmodtime, fmodby, fmodwith, potype, pmodtime, pmodby, pmodwith, xname, xdept, xtitle, xaddress, xphone1, xphone2, xmodtime, secure, created, creator, winhomedir, winprofiledir, sponsor_type, sponsor_id, expiration) VALUES (:login, :users_id, :uid, '/bin/athena/bash', 'cmd', NVL(:last, CHR(0)), NVL(:first, CHR(0)), NVL(:middle, CHR(0)), :st, NVL(:id, CHR(0)), NVL(:type, CHR(0)), SYSDATE, :who, :prog, NVL(:name, CHR(0)), NVL(:dept, CHR(0)), NVL(:haddr, CHR(0)), NVL(:hphone, CHR(0)), NVL(SUBSTR(:oaddr, 0, :oadlen), CHR(0)), NVL(SUBSTR(:ophone, 0, :ophlen), CHR(0)), SYSDATE, :who, :prog, 'NONE', SYSDATE, :who, :prog, NVL(SUBSTR(:name, 0, :xnlen), CHR(0)), NVL(:dept, CHR(0)), NVL(:xtitle, CHR(0)), NVL(:xaddress, CHR(0)), NVL(:xphone1, CHR(0)), NVL(:xphone2, CHR(0)), SYSDATE, :issecure, SYSDATE, :who, '[DFS]', '[DFS]', 'NONE', 0, CHR(0)); if (sqlca.sqlcode) { dbmserr("adding user", sqlca.sqlcode); exit(1); } } int set_next_users_id(void) { EXEC SQL BEGIN DECLARE SECTION; int flag, value, retval; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = 'users_id'; if (sqlfail()) sqlexit(); if (sqlca.sqlerrd[2] != 1) { EXEC SQL ROLLBACK; com_err(whoami, MR_INTERNAL, "values table inconsistancy"); exit(1); } flag = 0; EXEC SQL SELECT users_id INTO :flag FROM users WHERE users_id = :value; if (sqlfail()) sqlexit(); if (sqlca.sqlerrd[2] == 0) flag = 0; while (flag) { value++; flag = 0; EXEC SQL SELECT users_id INTO :flag FROM users WHERE users_id = :value; if (sqlfail()) sqlexit(); if (sqlca.sqlerrd[2] == 0) flag = 0; } retval = value++; EXEC SQL UPDATE numvalues SET value = :value WHERE name = 'users_id'; if (sqlca.sqlcode) { dbmserr("assigning ID", sqlca.sqlcode); exit(1); } return retval; } int set_next_uid(void) { EXEC SQL BEGIN DECLARE SECTION; int flag, initial, value, retval; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT value INTO :initial FROM numvalues WHERE name = 'unix_uid'; if (sqlfail()) sqlexit(); if (sqlca.sqlerrd[2] != 1) { EXEC SQL ROLLBACK; com_err(whoami, MR_INTERNAL, "values table inconsistancy"); exit(1); } value = initial; flag = 0; EXEC SQL SELECT COUNT(unix_uid) INTO :flag FROM users WHERE unix_uid = :value; if (sqlfail()) sqlexit(); if (sqlca.sqlerrd[2] == 0) flag = 0; while (flag) { value++; #ifdef ULTRIX_ID_HOLE if (value > 31999 && value < 32768) value = 32768; #endif if (value > MAX_ID_VALUE) value = MIN_ID_VALUE; if (value == initial) { com_err(whoami, 0, "Out of uids!"); EXEC SQL ROLLBACK WORK; exit(1); } flag = 0; EXEC SQL SELECT COUNT(unix_uid) INTO :flag FROM users WHERE unix_uid = :value; if (sqlfail()) sqlexit(); } retval = value++; if (value > MAX_ID_VALUE) value = MIN_ID_VALUE; EXEC SQL UPDATE numvalues SET value = :value WHERE name = 'unix_uid'; if (sqlca.sqlcode) { dbmserr("assigning ID", sqlca.sqlcode); exit(1); } return retval; } void sqlexit(void) { dbmserr(NULL, sqlca.sqlcode); EXEC SQL ROLLBACK WORK; exit(1); } void dbmserr(char *where, int what) { char err_msg[256]; int bufsize = 256, msglength = 0; sqlglm(err_msg, &bufsize, &msglength); err_msg[msglength] = '\0'; if (where) com_err(whoami, 0, "DBMS error %swhile %s", err_msg, where); else com_err(whoami, 0, "DBMS error %s", err_msg); }