X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/blobdiff_plain/85330553eb619f783e0480dfc2bc467a9b4afd7b..a2418844f8efe9082e523a20fc68c4574cf028a5:/server/qsetup.pc diff --git a/server/qsetup.pc b/server/qsetup.pc index 68785888..afd73bbb 100644 --- a/server/qsetup.pc +++ b/server/qsetup.pc @@ -32,9 +32,11 @@ EXEC SQL END DECLARE SECTION; EXEC SQL WHENEVER SQLERROR DO dbmserr(); - +int hostname_check(char *name); +int hostinfo_check(char *name, int num); int prefetch_value(struct query *q, char **argv, client *cl); int check_nfs(int mach_idx, char *name, char *access); +int check_mailman_listname(char *name, const char *suffix); /* Setup Routines */ @@ -60,6 +62,47 @@ int setup_ausr(struct query *q, char *argv[], client *cl) row = 2; else row = 1; + + if (q->version > 2) + { + if (strlen(argv[row + 3]) + strlen(argv[row + 4]) + + strlen(argv[row + 5]) + 2 > USERS_FULLNAME_SIZE) + return MR_ARG_TOO_LONG; + } + else + { + if (strlen(argv[row + 2]) + strlen(argv[row + 3]) + + strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE) + return MR_ARG_TOO_LONG; + } + + if (q->version > 10) + { + /* For both winhomedir and winprofiledir, we allow values of the + * following forms: + * + * [AFS] - Magic token for AFS home directory. + * [LOCAL] - Magic token for AD default local values, i.e. C:\ + * [DFS] - Magic token for DFS home directory + * UNC pathname - \\ + * local pathname - : + */ + + if ((strcasecmp(argv[row + 12], "[AFS]")) && + (strcasecmp(argv[row + 12], "[LOCAL]")) && + (strcasecmp(argv[row + 12], "[DFS]")) && + (!(argv[row + 12][0] == '\\' && argv[row + 12][1] == '\\')) && + (!(isalpha(*argv[row + 12]) && (argv[row + 12][1] == ':')))) + return MR_BAD_CHAR; + + if ((strcasecmp(argv[row + 13], "[AFS]")) && + (strcasecmp(argv[row + 13], "[LOCAL]")) && + (strcasecmp(argv[row + 13], "[DFS]")) && + (!(argv[row + 13][0] == '\\' && argv[row + 13][1] == '\\')) && + (!(isalpha(*argv[row + 13]) && (argv[row + 13][1] == ':')))) + return MR_BAD_CHAR; + } + if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1) { if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1))) @@ -76,6 +119,12 @@ int setup_ausr(struct query *q, char *argv[], client *cl) if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS) return mr_errcode; + /* If this is an UPDATE query, we're done. */ + if (row == 2) + return MR_SUCCESS; + + /* For an add query, we need to fill in the creator id. */ + sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id); return MR_SUCCESS; } @@ -88,17 +137,20 @@ int setup_dusr(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int flag, id, cnt; + char resv[USERS_RESERVATIONS_SIZE]; EXEC SQL END DECLARE SECTION; id = *(int *)argv[0]; - /* For now, only allow users to be deleted if their status is 0 */ - EXEC SQL SELECT status INTO :flag FROM users WHERE users_id = :id; - if (flag != 0 && flag != 4) + /* For now, only allow users to be deleted if their status is + * one of 0, 4, or 8 (the various registerable statuses) + * and we have no reservations about deleting them. + */ + EXEC SQL SELECT status, reservations INTO :flag, :resv + FROM users WHERE users_id = :id; + if ((flag != 0 && flag != 4 && flag != 8) || *resv) return MR_IN_USE; - EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER'; - EXEC SQL DELETE FROM krbmap WHERE users_id = :id; EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers WHERE member_id = :id AND member_type = 'USER'; if (cnt > 0) @@ -121,31 +173,9 @@ int setup_dusr(struct query *q, char *argv[], client *cl) return MR_IN_USE; if (dbms_errno) return mr_errcode; - return MR_SUCCESS; -} - -/* setup_spop: verify that there is already a valid POP machine_id in the - * pop_id field. Also take care of keeping track of the post office usage. - */ -int setup_spop(struct query *q, char *argv[], client *cl) -{ - EXEC SQL BEGIN DECLARE SECTION; - int id, mid; - char type[9]; - EXEC SQL END DECLARE SECTION; - - id = *(int *)argv[0]; - EXEC SQL SELECT potype, pop_id INTO :type, :mid FROM users - WHERE users_id = :id; - if (sqlca.sqlerrd[2] == 0) - return MR_MACHINE; - EXEC SQL SELECT mach_id INTO :mid FROM machine - WHERE mach_id = :mid; - if (sqlca.sqlerrd[2] == 0) - return MR_MACHINE; - if (strcmp(strtrim(type), "POP")) - set_pop_usage(mid, 1); + EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER'; + EXEC SQL DELETE FROM krbmap WHERE users_id = :id; return MR_SUCCESS; } @@ -156,7 +186,7 @@ int setup_dpob(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int id, user; - char type[9]; + char type[USERS_POTYPE_SIZE]; EXEC SQL END DECLARE SECTION; user = *(int *)argv[0]; @@ -203,15 +233,19 @@ int setup_dmac(struct query *q, char *argv[], client *cl) WHERE mach_id = :id; if (cnt > 0) return MR_IN_USE; - EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printcap + EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers WHERE mach_id = :id; if (cnt > 0) return MR_IN_USE; - EXEC SQL SELECT COUNT(quotaserver) INTO :cnt FROM printcap - WHERE quotaserver = :id; + EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers + WHERE rm = :id; + if (cnt > 0) + return MR_IN_USE; + EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers + WHERE rq = :id; if (cnt > 0) return MR_IN_USE; - EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM palladium + EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers WHERE mach_id = :id; if (cnt > 0) return MR_IN_USE; @@ -219,13 +253,70 @@ int setup_dmac(struct query *q, char *argv[], client *cl) WHERE mach_id = :id; if (cnt > 0) return MR_IN_USE; + EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers + WHERE member_type = 'MACHINE' and member_id = :id; + if (cnt > 0) + return MR_IN_USE; EXEC SQL DELETE FROM mcmap WHERE mach_id = :id; + if (dbms_errno) + return mr_errcode; + + EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id; if (dbms_errno) return mr_errcode; return MR_SUCCESS; } +/* setup_asnt - verify that the data entered for the subnet is sane. + * In particular, make sure that the "low" and "high" addresses are + * correctly ordered, i.e., high > low. + */ + +int setup_asnt(struct query *q, char *argv[], client *cl) +{ + int high, low, row, status; + char *account_number; + + /* Check for asnt or usnt. */ + if (q->type == APPEND) + row = 0; + else + row = 1; + + low = atoi(argv[row + 7]); + high = atoi(argv[row + 8]); + status = atoi(argv[row + 2]); + account_number = argv[row + 4]; + + /* Don't allow Private subnets to be created without a valid billing + * number. + */ + if (status == SNET_STATUS_PRIVATE_10MBPS || + status == SNET_STATUS_PRIVATE_100MBPS || + status == SNET_STATUS_PRIVATE_1000MBPS) + { + EXEC SQL SELECT account_number FROM accountnumbers + WHERE account_number = :account_number; + if (sqlca.sqlcode == SQL_NO_MATCH) + return MR_ACCOUNT_NUMBER; + } + + /* Special case 0.0.0.0 and 255.255.255.255 */ + if (!(low == 0 || low == -1 || high == 0 || high == -1)) + if (low > high) + return MR_ADDRESS; + + /* If this is update_subnet, we're done. */ + if (row == 1) + return MR_SUCCESS; + + /* For an add_subnet query, allocate and fill in a new snet_id */ + if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS) + return mr_errcode; + + return MR_SUCCESS; +} /* setup_dsnt - verify that the subnet is no longer being referenced * and may safely be deleted. @@ -277,17 +368,20 @@ int setup_dclu(struct query *q, char *argv[], client *cl) * a -1 there. Remember that this is also used for ulis, with the indexes * at 6 & 7. Also check that the list name does not contain uppercase * characters, control characters, @, or :. + * + * Newlines in list descriptions do bad things to the aliases file + * moira generates, so make sure the description doesn't contain any, too. */ static int badlistchars[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */ - 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */ + 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -298,25 +392,62 @@ static int badlistchars[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; +static const char *mailman_suffixes[] = { "-admin", "-owner", "-request", + "-bounces", "-confirm", "-join", + "-leave", "-subscribe", + "-unsubscribe", NULL }; + int setup_alis(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; - int ngid; + int ngid, cnt, mailman, mailman_id, lid; + char *name, *desc; EXEC SQL END DECLARE SECTION; unsigned char *p; - int idx, err; + int idx, err, best = -1, usage, i; if (!strcmp(q->shortname, "alis")) idx = 0; else if (!strcmp(q->shortname, "ulis")) idx = 1; + name = argv[idx]; + + if (q->version == 2) + desc = argv[9 + idx]; + else if (q->version == 3) + desc = argv[10 + idx]; + else if (q->version == 4) + desc = argv[12 + idx]; + else if (q->version >= 10) + desc = argv[14 + idx]; + + if (idx == 1) + { + lid = *(int *)argv[0]; - for (p = (unsigned char *) argv[idx]; *p; p++) + if (acl_access_check(lid, cl)) + return MR_PERM; + } + + for (p = (unsigned char *) name; *p; p++) { if (badlistchars[*p]) return MR_BAD_CHAR; } + for (p = (unsigned char *) desc; *p; p++) + { + if (*p == '\n') + return MR_BAD_CHAR; + } + + /* Check that it doesn't conflict with a pre-existing weirdly-cased + * name. */ + EXEC SQL SELECT COUNT(name) INTO :cnt FROM list + WHERE LOWER(name) = :name AND name != :name; + if (cnt) + return MR_EXISTS; + if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1) { if (atoi(argv[5 + idx])) @@ -333,6 +464,89 @@ int setup_alis(struct query *q, char *argv[], client *cl) strcpy(argv[6 + idx], "-1"); } + /* Don't let someone rename a list to one of the magic mailman names + * (foo-admin, etc) if foo already exists as a mailman list. + */ + for (i = 0; mailman_suffixes[i]; i++) + { + if ((err = check_mailman_listname(name, mailman_suffixes[i])) + != MR_SUCCESS) + return err; + } + + if (q->version >= 10) + { + /* Don't let them take this name for a mailman list if we can't + * reserve the -admin, -owner, and -request names. + */ + if (atoi(argv[8 + idx])) + { + EXEC SQL SELECT COUNT(name) INTO :cnt FROM list + WHERE (name = :name || '-admin' OR name = :name || '-owner' OR + name = :name || '-request'); + if (cnt) + return MR_EXISTS; + } + + /* Handle the [ANY] case for mailman server. */ + mailman_id = *(int *)argv[9 + idx]; + if (mailman_id == -1) + { + EXEC SQL DECLARE csr_mailman CURSOR FOR + SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN' + AND enable = 1; + if (dbms_errno) + return mr_errcode; + EXEC SQL OPEN csr_mailman; + if (dbms_errno) + return mr_errcode; + + while (1) + { + EXEC SQL FETCH csr_mailman INTO :mailman_id; + if (sqlca.sqlcode) + break; + + EXEC SQL SELECT COUNT(name) INTO :usage FROM list + WHERE mailman_id = :mailman_id; + + if (best < 0 || usage < best) + { + best = usage; + *(int *)argv[9 + idx] = mailman_id; + break; + } + } + EXEC SQL CLOSE csr_mailman; + if (dbms_errno) + return mr_errcode; + + if (best == -1) + return MR_SERVICE; + } + } + else + { + /* Client too old to know about the mailman code. + * Use existing value of mailman boolean in the table. + * Don't do this for add_list from an old client, since the row + * they're creating won't exist yet, and there's no way for them to + * create a list with the mailman bit set, anyway. + */ + if (idx == 1) + { + EXEC SQL SELECT mailman INTO :mailman FROM list WHERE list_id = :lid; + if (mailman) + { + EXEC SQL SELECT COUNT(name) INTO :cnt FROM list + WHERE (name = :name || '-admin' OR name = :name || '-owner' OR + name = :name || '-request'); + if (cnt) + return MR_EXISTS; + } + } + } + if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS) return mr_errcode; @@ -381,6 +595,11 @@ int setup_dlis(struct query *q, char *argv[], client *cl) if (cnt > 0) return MR_IN_USE; + EXEC SQL SELECT COUNT(name) INTO :cnt FROM list + WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id; + if (cnt > 0) + return MR_IN_USE; + EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers WHERE acl_id = :id AND acl_type = 'LIST'; if (cnt > 0) @@ -400,7 +619,29 @@ int setup_dlis(struct query *q, char *argv[], client *cl) WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id OR z.sub_type = 'LIST' AND z.sub_id = :id OR z.iws_type = 'LIST' AND z.iws_id = :id - OR z.iui_type = 'LIST' AND z.iui_id = :id; + OR z.iui_type = 'LIST' AND z.iui_id = :id + OR z.owner_type = 'LIST' and z.owner_id = :id; + if (cnt > 0) + return MR_IN_USE; + + EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers + WHERE lpc_acl = :id OR ac = :id; + if (cnt > 0) + return MR_IN_USE; + + EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers + WHERE owner_type = 'LIST' AND owner_id = :id + OR lpc_acl = :id; + if (cnt > 0) + return MR_IN_USE; + + EXEC SQL SELECT count(name) INTO :cnt FROM containers + WHERE acl_id = :id AND acl_type = 'LIST'; + if (cnt > 0) + return MR_IN_USE; + + EXEC SQL SELECT count(name) INTO :cnt FROM containers + WHERE memacl_id = :id AND memacl_type = 'LIST'; if (cnt > 0) return MR_IN_USE; @@ -473,7 +714,7 @@ int setup_dshi(struct query *q, char *argv[], client *cl) ** Description: ** - for type = RVD: ** * allow anything - ** - for type = NFS: + ** - for type = NFS/IMAP: ** * extract directory prefix from name ** * verify mach_id/dir in nfsphys ** * verify rwaccess in {r, w, R, W} @@ -497,7 +738,7 @@ int setup_afil(struct query *q, char *argv[], client *cl) int mach_id; EXEC SQL BEGIN DECLARE SECTION; int ok; - char ftype[32], *rwaccess; + char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess; EXEC SQL END DECLARE SECTION; type = argv[1]; @@ -517,7 +758,7 @@ int setup_afil(struct query *q, char *argv[], client *cl) if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS) return mr_errcode; - if (!strcmp(type, "NFS")) + if (!strcmp(type, "NFS") || !strcmp(type, "IMAP")) return check_nfs(mach_id, name, rwaccess); return MR_SUCCESS; @@ -535,7 +776,7 @@ int setup_ufil(struct query *q, char *argv[], client *cl) char *type, *name; EXEC SQL BEGIN DECLARE SECTION; int fid, total, who, ok; - char *entity, ftype[32], *access; + char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access; short int total_null; EXEC SQL END DECLARE SECTION; @@ -561,7 +802,7 @@ int setup_ufil(struct query *q, char *argv[], client *cl) if (dbms_errno) return mr_errcode; - if (!strcmp(type, "NFS")) + if (!strcmp(type, "NFS") || !strcmp(type, "IMAP")) { status = check_nfs(mach_id, name, access); EXEC SQL UPDATE quota SET phys_id = :_var_phys_id @@ -608,7 +849,7 @@ int setup_ufil(struct query *q, char *argv[], client *cl) int check_nfs(int mach_id, char *name, char *access) { EXEC SQL BEGIN DECLARE SECTION; - char dir[81]; + char dir[NFSPHYS_DIR_SIZE]; int mid = mach_id; EXEC SQL END DECLARE SECTION; int status; @@ -747,32 +988,6 @@ int setup_dqot(struct query *q, char **argv, client *cl) } -/* setup add_kerberos_user_mapping: add the string to the string - * table if necessary. - */ - -int setup_akum(struct query *q, char **argv, client *cl) -{ - EXEC SQL BEGIN DECLARE SECTION; - int id; - char *name; - EXEC SQL END DECLARE SECTION; - - name = argv[1]; - if (name_to_id(name, STRINGS_TABLE, &id) != MR_SUCCESS) - { - if (q->type != APPEND) - return MR_STRING; - id = add_string(name); - cache_entry(name, STRINGS_TABLE, id); - } - if (dbms_errno) - return mr_errcode; - *(int *)argv[1] = id; - return MR_SUCCESS; -} - - /* prefetch_value(): * This routine fetches an appropriate value from the numvalues table. * It is a little hack to get around the fact that SQL doesn't let you @@ -843,18 +1058,34 @@ int prefetch_filesys(struct query *q, char **argv, client *cl) } +/* setup_ghst(): + */ + +int setup_ghst(struct query *q, char **argv, client *cl) +{ + if (strcmp(argv[0], "*") || strcmp(argv[1], "*") || + strcmp(argv[2], "*") || strcmp(argv[3], "*")) + return MR_SUCCESS; + else + return MR_PERM; +} + /* setup_ahst(): */ int setup_ahst(struct query *q, char **argv, client *cl) { EXEC SQL BEGIN DECLARE SECTION; - char *name, oldname[41], vendor[17], model[25], os[17]; - int value, id, saddr, mask, high, low, cnt; + char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE]; + char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE]; + int value, id, ssaddr, smask, shigh, slow, cnt; + unsigned int saddr, mask, high, low; EXEC SQL END DECLARE SECTION; - int row; + int row, idx; struct in_addr addr; + id = *(int *)argv[0]; + if (!strcmp(q->shortname, "uhst")) { row = 1; @@ -865,106 +1096,49 @@ int setup_ahst(struct query *q, char **argv, client *cl) else row = 0; - id = *(int *)argv[0]; - - /* sanity check name: must start with a letter, contain only - * letters, numerals, and hyphen, and not end with a hyphen. - */ - if (row == 0 || strcmp(argv[1], oldname)) - { - char *p = argv[row]; - - if (!isalpha(*p)) - return MR_BAD_CHAR; - for (; *p; p++) - { - if ((!isalnum(*p) && *p != '-' && *p != '.') || - (*p == '-' && p[1] == '.')) - return MR_BAD_CHAR; - } - if (*(p - 1) == '-') - return MR_BAD_CHAR; - } - - /* sanity check host vendor: must start with a letter, contain only - * letters, numerals, and hyphen, and end with an alphanumeric. - */ - if (*argv[row + 1] && (row == 0 || strcmp(argv[2], vendor))) - { - char *p = argv[row + 1]; - - if (!isalpha(*p)) - return MR_BAD_CHAR; - for (; *p; p++) - { - if ((!isalnum(*p) && *p != '-' && *p != '.') || - (*p == '-' && p[1] == '.')) - return MR_BAD_CHAR; - } - if (!isalnum(*(p - 1))) - return MR_BAD_CHAR; - } - - /* sanity check host type: must start with a letter, contain only - * letters, numerals, and hyphen, and end with an alphanumeric. - */ - if (*argv[row + 2] && (row == 0 || strcmp(argv[3], model))) - { - char *p = argv[row + 2]; - - if (!isalnum(*p)) - return MR_BAD_CHAR; - for (; *p; p++) - { - if ((!isalnum(*p) && *p != '-' && *p != '.') || - (*p == '-' && p[1] == '.')) - return MR_BAD_CHAR; - } - if (!isalnum(*(p - 1))) - return MR_BAD_CHAR; - } - - /* sanity check host os: must start with a letter, contain only - * letters, numerals, and hyphen, and end with an hyphen alphanumeric. - */ - if (*argv[row + 3] && (row == 0 || strcmp(argv[4], os))) - { - char *p = argv[row + 3]; + if (q->version < 6) + idx = 0; + else if (q->version >= 6 && q->version < 8) + idx = 1; + else + idx = 2; - if (!isalpha(*p)) - return MR_BAD_CHAR; - for (; *p; p++) - { - if ((!isalnum(*p) && *p != '-' && *p != '.') || - (*p == '-' && p[1] == '.')) - return MR_BAD_CHAR; - } - if (!isalnum(*(p - 1))) - return MR_BAD_CHAR; - } + /* Sanity check name, vendor, model, and os. */ + if ((row == 0 || strcasecmp(argv[1], oldname)) && + !hostname_check(argv[row])) + return MR_BAD_CHAR; + if ((row == 0 || strcasecmp(argv[2], vendor)) && + !hostinfo_check(argv[row + 1], 0)) + return MR_BAD_CHAR; + if ((row == 0 || strcasecmp(argv[3], model)) && + !hostinfo_check(argv[row + 2], 1)) + return MR_BAD_CHAR; + if ((row == 0 || strcasecmp(argv[4], os)) && + !hostinfo_check(argv[row + 3], 0)) + return MR_BAD_CHAR; /* check for duplicate name */ name = argv[row]; EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias - WHERE name = :name; + WHERE name = UPPER(:name); if (dbms_errno) return mr_errcode; if (cnt != 0) return MR_EXISTS; /* check address */ - if (!strcmp(argv[9 + row], "unassigned")) + if (!strcmp(argv[9 + row + idx], "unassigned")) value = -1; - else if (!strcmp(argv[9 + row], "unique")) + else if (!strcmp(argv[9 + row + idx], "unique")) { - if (*(int *)argv[8 + row] == 0) + if (*(int *)argv[8 + row + idx] == 0) value = -1; else value = -2; } else { - value = ntohl(inet_addr(argv[9 + row])); + value = ntohl(inet_addr(argv[9 + row + idx])); if (value == -1) return MR_ADDRESS; } @@ -975,11 +1149,15 @@ int setup_ahst(struct query *q, char **argv, client *cl) /* * an address or unique was specified. */ - id = *(int *)argv[8 + row]; - EXEC SQL SELECT saddr, mask, high, low INTO :saddr, :mask, :high, :low - FROM subnet WHERE snet_id = :id; + id = *(int *)argv[8 + row + idx]; + EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask, + :shigh, :slow FROM subnet WHERE snet_id = :id; if (dbms_errno) return mr_errcode; + saddr = (unsigned) ssaddr; + mask = (unsigned) smask; + high = (unsigned) shigh; + low = (unsigned) slow; if (value != -2) { /* @@ -995,7 +1173,7 @@ int setup_ahst(struct query *q, char **argv, client *cl) * link in an inet_addr() that returns an error for * this case. */ - addr.s_addr = inet_addr(argv[9 + row]); + addr.s_addr = inet_addr(argv[9 + row + idx]); name = inet_ntoa(addr); EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE address = :name; @@ -1039,7 +1217,7 @@ int setup_ahst(struct query *q, char **argv, client *cl) break; } if (cnt != 0) - return MR_ADDRESS; + return MR_NO_ID; else value = htonl(id); } @@ -1047,13 +1225,13 @@ int setup_ahst(struct query *q, char **argv, client *cl) * we have an address in value. Convert it to a string and store it. */ addr.s_addr = htonl(value); - strcpy(argv[9 + row], inet_ntoa(addr)); + strcpy(argv[9 + row + idx], inet_ntoa(addr)); } else - strcpy(argv[9 + row], "unassigned"); + strcpy(argv[9 + row + idx], "unassigned"); /* status checking */ - value = atoi(argv[7 + row]); + value = atoi(argv[7 + row + idx]); if (row == 0 && !(value == 1 || value == 0)) return MR_TYPE; if (row == 1) @@ -1098,24 +1276,352 @@ int setup_ahal(struct query *q, char **argv, client *cl) EXEC SQL END DECLARE SECTION; char *p; - p = name = argv[0]; - if (!isalpha(*p)) + name = argv[0]; + if (!hostname_check(argv[0])) return MR_BAD_CHAR; - for (; *p; p++) + + EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE + name = UPPER(:name); + if (dbms_errno) + return mr_errcode; + if (cnt > 0) + return MR_EXISTS; + + return MR_SUCCESS; +} + +/* setup_uhha(): Check characters in hwaddr, and make sure it's not + * a duplicate. + */ +int setup_uhha(struct query *q, char **argv, client *cl) +{ + EXEC SQL BEGIN DECLARE SECTION; + char *hwaddr = argv[1]; + int count; + EXEC SQL END DECLARE SECTION; + char *p; + + if (*hwaddr && strcasecmp(hwaddr, "unknown")) { - if ((!isalnum(*p) && *p != '-' && *p != '.') || - (*p == '-' && p[1] == '.')) - return MR_BAD_CHAR; + for (p = hwaddr; *p; p++) + { + if (isupper(*p)) + *p = tolower(*p); + if (!isxdigit(*p)) + return MR_BAD_CHAR; + } + if (p != hwaddr + 12) + return MR_ADDRESS; + + EXEC SQL SELECT COUNT(hwaddr) INTO :count + FROM machine WHERE hwaddr = :hwaddr; + if (count) + return MR_NOT_UNIQUE; } - if (*(p - 1) == '-') + + return MR_SUCCESS; +} + +/* setup_aprn(): Make sure name/duplexname don't conflict with + * anything. If [ANY] was specified for the spooling host, pick the + * least loaded print server that serves this kind of printer. + */ +int setup_aprn(struct query *q, char **argv, client *cl) +{ + int best = -1, row; + char *p; + EXEC SQL BEGIN DECLARE SECTION; + int mid, usage, count; + char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname; + EXEC SQL END DECLARE SECTION; + + /* Check for aprn or uprn. */ + if (q->type == APPEND) + row = 0; + else + row = 1; + + name = argv[PRN_NAME + row]; + duplexname = argv[PRN_DUPLEXNAME + row]; + oldname = argv[0]; + + if (!*name) return MR_BAD_CHAR; + else + { + if (q->type == APPEND) + { + EXEC SQL SELECT COUNT(name) INTO :count FROM printers + WHERE name = :name OR duplexname = :name; + } + else + { + EXEC SQL SELECT COUNT(name) INTO :count FROM printers + WHERE ( name = :name OR duplexname = :name ) + AND name != :oldname; + } + if (dbms_errno) + return mr_errcode; + if (count) + return MR_NOT_UNIQUE; + } + + if (*duplexname) + { + if (q->type == APPEND) + { + EXEC SQL SELECT COUNT(name) INTO :count FROM printers + WHERE name = :duplexname OR duplexname = :duplexname; + } + else + { + EXEC SQL SELECT COUNT(name) INTO :count FROM printers + WHERE ( name = :duplexname OR duplexname = :duplexname ) + AND name != :oldname; + } + + if (dbms_errno) + return mr_errcode; + if (count) + return MR_NOT_UNIQUE; + } + + if (!strcmp(name, duplexname)) + return MR_NOT_UNIQUE; + + mid = *(int *)argv[PRN_RM + row]; + if (mid == -1) + { + EXEC SQL DECLARE csr_rm CURSOR FOR + SELECT ps.mach_id, s.string FROM printservers ps, strings s + WHERE ps.mach_id IN + ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT' + AND enable = 1 ) + AND ps.printer_types = s.string_id; + if (dbms_errno) + return mr_errcode; + EXEC SQL OPEN csr_rm; + if (dbms_errno) + return mr_errcode; + + while (1) + { + EXEC SQL FETCH csr_rm INTO :mid, :types; + if (sqlca.sqlcode) + break; + + for (p = strtok(types, ", "); p; p = strtok(NULL, ", ")) + { + if (!strcasecmp(argv[PRN_TYPE + row], p)) + { + EXEC SQL SELECT COUNT(name) INTO :usage + FROM printers WHERE rm = :mid; + + if (best < 0 || usage < best) + { + best = usage; + *(int *)argv[PRN_RM + row] = mid; + break; + } + } + } + } + EXEC SQL CLOSE csr_rm; + if (dbms_errno) + return mr_errcode; + + if (best == -1) + return MR_SERVICE; + } + else + { + EXEC SQL SELECT mach_id INTO :mid FROM printservers + WHERE mach_id = :mid; + if (sqlca.sqlcode) + return MR_SERVICE; + } + + return MR_SUCCESS; +} + +int setup_dpsv(struct query *q, char **argv, client *cl) +{ + int id; + EXEC SQL BEGIN DECLARE SECTION; + int cnt; + EXEC SQL END DECLARE SECTION; + + id = *(int *)argv[0]; + + EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers + WHERE rm = :id; + if (cnt > 0) + return MR_IN_USE; + + return MR_SUCCESS; +} + +int setup_dcon(struct query *q, char *argv[], client *cl) +{ + EXEC SQL BEGIN DECLARE SECTION; + int id, cnt; + char containername[CONTAINERS_NAME_SIZE]; + EXEC SQL END DECLARE SECTION; + + id = *(int *)argv[0]; + /* check to see if there are machines in this container */ + EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap + WHERE cnt_id = :id; + if (cnt > 0) + return MR_IN_USE; + + /* check to see if there are subcontainers in this container */ + + /* get the container name */ + + EXEC SQL SELECT name INTO :containername + FROM containers + WHERE cnt_id = :id; + + /* trim off the trailing spaces */ + strcpy(containername, strtrim(containername)); + + EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers + WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%'); + + if (cnt > 0) + return MR_IN_USE; - EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE - name = :name; if (dbms_errno) return mr_errcode; - if (cnt > 0) + return MR_SUCCESS; +} + +int setup_scli(struct query *q, char *argv[], client *cl) +{ + EXEC SQL BEGIN DECLARE SECTION; + int cnt_id, list_id; + EXEC SQL END DECLARE SECTION; + + cnt_id = *(int *)argv[0]; + /* Check if someone has already set the list for this container */ + EXEC SQL SELECT list_id INTO :list_id FROM containers + WHERE cnt_id = :cnt_id; + if (list_id != 0) return MR_EXISTS; + if (dbms_errno) + return mr_errcode; + + return MR_SUCCESS; +} + +/* hostname_check() + * validate the rfc1035/rfc1123-ness of a hostname + */ + +int hostname_check(char *name) +{ + char *p; + int count; + + /* Sanity check name: must contain only letters, numerals, and + * hyphen, and not start or end with a hyphen. Also make sure no + * label (the thing the .s seperate) is longer than 63 characters, + * or empty. + */ + + for (p = name, count = 0; *p; p++) + { + count++; + if ((!isalnum(*p) && *p != '-' && *p != '.') || + (*p == '-' && p[1] == '.')) + return 0; + if (*p == '.') + { + if (count == 1) + return 0; + count = 0; + } + if (count == 64) + return 0; + } + if (*(p - 1) == '-') + return 0; + return 1; +} + +int hostinfo_check(char *info, int num) +{ + char *p; + + if (!*info) + return 1; + + /* Sanity check host hostinfo: must start with a letter (or number + * if num is true), contain only letters, numerals, and hyphen, and + * not end with a hyphen. + */ + + if (!isalpha(*info) && (!num || !isdigit(*info))) + return 0; + for (p = info; *p; p++) + { + if ((!isalnum(*p) && *p != '-' && *p != '.') || + (*p == '-' && p[1] == '.')) + return 0; + } + if (!isalnum(*(p - 1))) + return 1; +} + +int setup_acon(struct query *q, char *argv[], client *cl) +{ + EXEC SQL BEGIN DECLARE SECTION; + char containername[CONTAINERS_NAME_SIZE]; + EXEC SQL END DECLARE SECTION; + + char* ptr; + + memset(containername, 0, sizeof(containername)); + strcpy(containername, argv[0]); + ptr = strrchr(containername, '/'); + /* sub container, check for parents */ + if (ptr) + { + *ptr = '\0'; + EXEC SQL SELECT * FROM containers + WHERE lower(name) = lower(:containername); + if (sqlca.sqlerrd[2] != 1) + return MR_CONTAINER_NO_PARENT; + } + + if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS) + return mr_errcode; + + return MR_SUCCESS; +} + +int check_mailman_listname(char *name, const char *suffix) +{ + char *p; + EXEC SQL BEGIN DECLARE SECTION; + int i, cnt; + EXEC SQL END DECLARE SECTION; + + p = strstr(name, suffix); + if (p) + { + if (strlen(name) == (p - name + strlen(suffix))) + { + /* list is of the form "name-suffix" */ + i = (p - name); + EXEC SQL SELECT COUNT(name) INTO :cnt FROM list + WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1; + if (cnt > 0) + return MR_EXISTS; + } + } + return MR_SUCCESS; }