| 1 | /* |
| 2 | |
| 3 | This code is not copyright, and is placed in the public domain. Feel free to |
| 4 | use and modify. Please send modifications and/or suggestions + bug fixes to |
| 5 | |
| 6 | Klas Heggemann <klas@nada.kth.se> |
| 7 | |
| 8 | */ |
| 9 | |
| 10 | /* |
| 11 | * $FreeBSD: src/usr.sbin/bootparamd/bootparamd/bootparamd.c,v 1.10 1999/08/28 01:15:39 peter Exp $ |
| 12 | * $DragonFly: src/usr.sbin/bootparamd/bootparamd/bootparamd.c,v 1.4 2003/11/15 23:33:35 eirikn Exp $ |
| 13 | */ |
| 14 | #include <rpc/rpc.h> |
| 15 | #include <rpcsvc/yp_prot.h> |
| 16 | #include <rpcsvc/ypclnt.h> |
| 17 | #include "bootparam_prot.h" |
| 18 | #include <ctype.h> |
| 19 | #include <err.h> |
| 20 | #include <netdb.h> |
| 21 | #include <stdio.h> |
| 22 | #include <string.h> |
| 23 | #include <syslog.h> |
| 24 | #include <unistd.h> |
| 25 | #include <sys/types.h> |
| 26 | #include <sys/socket.h> |
| 27 | extern int debug, dolog; |
| 28 | extern unsigned long route_addr; |
| 29 | extern char *bootpfile; |
| 30 | |
| 31 | #define MAXLEN 800 |
| 32 | |
| 33 | struct hostent *he; |
| 34 | static char buffer[MAXLEN]; |
| 35 | static char hostname[MAX_MACHINE_NAME]; |
| 36 | static char askname[MAX_MACHINE_NAME]; |
| 37 | static char path[MAX_PATH_LEN]; |
| 38 | static char domain_name[MAX_MACHINE_NAME]; |
| 39 | |
| 40 | int getthefile(char *, char *, char *, int); |
| 41 | int checkhost(char *, char *, int); |
| 42 | |
| 43 | bp_whoami_res * |
| 44 | bootparamproc_whoami_1(bp_whoami_arg *whoami) |
| 45 | { |
| 46 | long haddr; |
| 47 | static bp_whoami_res res; |
| 48 | if (debug) |
| 49 | fprintf(stderr,"whoami got question for %d.%d.%d.%d\n", |
| 50 | 255 & whoami->client_address.bp_address_u.ip_addr.net, |
| 51 | 255 & whoami->client_address.bp_address_u.ip_addr.host, |
| 52 | 255 & whoami->client_address.bp_address_u.ip_addr.lh, |
| 53 | 255 & whoami->client_address.bp_address_u.ip_addr.impno); |
| 54 | if (dolog) |
| 55 | syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n", |
| 56 | 255 & whoami->client_address.bp_address_u.ip_addr.net, |
| 57 | 255 & whoami->client_address.bp_address_u.ip_addr.host, |
| 58 | 255 & whoami->client_address.bp_address_u.ip_addr.lh, |
| 59 | 255 & whoami->client_address.bp_address_u.ip_addr.impno); |
| 60 | |
| 61 | bcopy((char *)&whoami->client_address.bp_address_u.ip_addr, (char *)&haddr, |
| 62 | sizeof(haddr)); |
| 63 | he = gethostbyaddr(&haddr,sizeof(haddr),AF_INET); |
| 64 | if ( ! he ) goto failed; |
| 65 | |
| 66 | if (debug) warnx("this is host %s", he->h_name); |
| 67 | if (dolog) syslog(LOG_NOTICE,"This is host %s\n", he->h_name); |
| 68 | |
| 69 | strncpy(askname, he->h_name, sizeof(askname)); |
| 70 | askname[sizeof(askname)-1] = 0; |
| 71 | |
| 72 | if (checkhost(askname, hostname, sizeof hostname) ) { |
| 73 | res.client_name = hostname; |
| 74 | getdomainname(domain_name, MAX_MACHINE_NAME); |
| 75 | res.domain_name = domain_name; |
| 76 | |
| 77 | if ( res.router_address.address_type != IP_ADDR_TYPE ) { |
| 78 | res.router_address.address_type = IP_ADDR_TYPE; |
| 79 | bcopy( &route_addr, &res.router_address.bp_address_u.ip_addr, 4); |
| 80 | } |
| 81 | if (debug) fprintf(stderr, |
| 82 | "Returning %s %s %d.%d.%d.%d\n", |
| 83 | res.client_name, |
| 84 | res.domain_name, |
| 85 | 255 & res.router_address.bp_address_u.ip_addr.net, |
| 86 | 255 & res.router_address.bp_address_u.ip_addr.host, |
| 87 | 255 & res.router_address.bp_address_u.ip_addr.lh, |
| 88 | 255 & res.router_address.bp_address_u.ip_addr.impno); |
| 89 | if (dolog) syslog(LOG_NOTICE, |
| 90 | "Returning %s %s %d.%d.%d.%d\n", |
| 91 | res.client_name, |
| 92 | res.domain_name, |
| 93 | 255 & res.router_address.bp_address_u.ip_addr.net, |
| 94 | 255 & res.router_address.bp_address_u.ip_addr.host, |
| 95 | 255 & res.router_address.bp_address_u.ip_addr.lh, |
| 96 | 255 & res.router_address.bp_address_u.ip_addr.impno); |
| 97 | |
| 98 | return(&res); |
| 99 | } |
| 100 | failed: |
| 101 | if (debug) warnx("whoami failed"); |
| 102 | if (dolog) syslog(LOG_NOTICE,"whoami failed\n"); |
| 103 | return(NULL); |
| 104 | } |
| 105 | |
| 106 | |
| 107 | bp_getfile_res * |
| 108 | bootparamproc_getfile_1(bp_getfile_arg *getfile) |
| 109 | { |
| 110 | char *where, *index(); |
| 111 | static bp_getfile_res res; |
| 112 | |
| 113 | if (debug) |
| 114 | warnx("getfile got question for \"%s\" and file \"%s\"", |
| 115 | getfile->client_name, getfile->file_id); |
| 116 | |
| 117 | if (dolog) |
| 118 | syslog(LOG_NOTICE,"getfile got question for \"%s\" and file \"%s\"\n", |
| 119 | getfile->client_name, getfile->file_id); |
| 120 | |
| 121 | he = NULL; |
| 122 | he = gethostbyname(getfile->client_name); |
| 123 | if (! he ) goto failed; |
| 124 | |
| 125 | strncpy(askname, he->h_name, sizeof(askname)); |
| 126 | askname[sizeof(askname)-1] = 0; |
| 127 | |
| 128 | if (getthefile(askname, getfile->file_id,buffer,sizeof(buffer))) { |
| 129 | if ( (where = index(buffer,':')) ) { |
| 130 | /* buffer is re-written to contain the name of the info of file */ |
| 131 | strncpy(hostname, buffer, where - buffer); |
| 132 | hostname[where - buffer] = '\0'; |
| 133 | where++; |
| 134 | strcpy(path, where); |
| 135 | he = gethostbyname(hostname); |
| 136 | if ( !he ) goto failed; |
| 137 | bcopy( he->h_addr, &res.server_address.bp_address_u.ip_addr, 4); |
| 138 | res.server_name = hostname; |
| 139 | res.server_path = path; |
| 140 | res.server_address.address_type = IP_ADDR_TYPE; |
| 141 | } |
| 142 | else { /* special for dump, answer with null strings */ |
| 143 | if (!strcmp(getfile->file_id, "dump")) { |
| 144 | res.server_name = ""; |
| 145 | res.server_path = ""; |
| 146 | res.server_address.address_type = IP_ADDR_TYPE; |
| 147 | bzero(&res.server_address.bp_address_u.ip_addr,4); |
| 148 | } else goto failed; |
| 149 | } |
| 150 | if (debug) |
| 151 | fprintf(stderr, "returning server:%s path:%s address: %d.%d.%d.%d\n", |
| 152 | res.server_name, res.server_path, |
| 153 | 255 & res.server_address.bp_address_u.ip_addr.net, |
| 154 | 255 & res.server_address.bp_address_u.ip_addr.host, |
| 155 | 255 & res.server_address.bp_address_u.ip_addr.lh, |
| 156 | 255 & res.server_address.bp_address_u.ip_addr.impno); |
| 157 | if (dolog) |
| 158 | syslog(LOG_NOTICE, "returning server:%s path:%s address: %d.%d.%d.%d\n", |
| 159 | res.server_name, res.server_path, |
| 160 | 255 & res.server_address.bp_address_u.ip_addr.net, |
| 161 | 255 & res.server_address.bp_address_u.ip_addr.host, |
| 162 | 255 & res.server_address.bp_address_u.ip_addr.lh, |
| 163 | 255 & res.server_address.bp_address_u.ip_addr.impno); |
| 164 | return(&res); |
| 165 | } |
| 166 | failed: |
| 167 | if (debug) warnx("getfile failed for %s", getfile->client_name); |
| 168 | if (dolog) syslog(LOG_NOTICE, |
| 169 | "getfile failed for %s\n", getfile->client_name); |
| 170 | return(NULL); |
| 171 | } |
| 172 | |
| 173 | /* getthefile return 1 and fills the buffer with the information |
| 174 | of the file, e g "host:/export/root/client" if it can be found. |
| 175 | If the host is in the database, but the file is not, the buffer |
| 176 | will be empty. (This makes it possible to give the special |
| 177 | empty answer for the file "dump") */ |
| 178 | |
| 179 | int |
| 180 | getthefile(char *askname, char *fileid, char *buffer, int blen) |
| 181 | { |
| 182 | FILE *bpf; |
| 183 | char *where; |
| 184 | static char *result; |
| 185 | int resultlen; |
| 186 | static char *yp_domain; |
| 187 | |
| 188 | int ch, pch, fid_len, res = 0; |
| 189 | int match = 0; |
| 190 | char info[MAX_FILEID + MAX_PATH_LEN+MAX_MACHINE_NAME + 3]; |
| 191 | |
| 192 | bpf = fopen(bootpfile, "r"); |
| 193 | if ( ! bpf ) |
| 194 | errx(1, "no %s", bootpfile); |
| 195 | |
| 196 | /* XXX see comment below */ |
| 197 | while ( fscanf(bpf, "%255s", hostname) > 0 && !match ) { |
| 198 | if ( *hostname != '#' ) { /* comment */ |
| 199 | if ( ! strcmp(hostname, askname) ) { |
| 200 | match = 1; |
| 201 | } else { |
| 202 | he = gethostbyname(hostname); |
| 203 | if (he && !strcmp(he->h_name, askname)) match = 1; |
| 204 | } |
| 205 | } |
| 206 | if (*hostname == '+' ) { /* NIS */ |
| 207 | if (yp_get_default_domain(&yp_domain)) { |
| 208 | if (debug) warn("NIS"); |
| 209 | return(0); |
| 210 | } |
| 211 | if (yp_match(yp_domain, "bootparams", askname, strlen(askname), |
| 212 | &result, &resultlen)) |
| 213 | return (0); |
| 214 | if (strstr(result, fileid) == NULL) { |
| 215 | buffer[0] = '\0'; |
| 216 | } else { |
| 217 | snprintf(buffer, blen, |
| 218 | "%s",strchr(strstr(result,fileid), '=') + 1); |
| 219 | if (strchr(buffer, ' ') != NULL) |
| 220 | *(char *)(strchr(buffer, ' ')) = '\0'; |
| 221 | } |
| 222 | if (fclose(bpf)) |
| 223 | warnx("could not close %s", bootpfile); |
| 224 | return(1); |
| 225 | } |
| 226 | /* skip to next entry */ |
| 227 | if ( match ) break; |
| 228 | pch = ch = getc(bpf); |
| 229 | while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) { |
| 230 | pch = ch; ch = getc(bpf); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | /* if match is true we read the rest of the line to get the |
| 235 | info of the file */ |
| 236 | |
| 237 | if (match) { |
| 238 | fid_len = strlen(fileid); |
| 239 | while ( ! res && (fscanf(bpf,"%s", info)) > 0) { /* read a string */ |
| 240 | ch = getc(bpf); /* and a character */ |
| 241 | if ( *info != '#' ) { /* Comment ? */ |
| 242 | if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') { |
| 243 | where = info + fid_len + 1; |
| 244 | if ( isprint( *where )) { |
| 245 | strcpy(buffer, where); /* found file */ |
| 246 | res = 1; break; |
| 247 | } |
| 248 | } else { |
| 249 | while (isspace(ch) && ch != '\n') ch = getc(bpf); |
| 250 | /* read to end of line */ |
| 251 | if ( ch == '\n' ) { /* didn't find it */ |
| 252 | res = -1; break; /* but host is there */ |
| 253 | } |
| 254 | if ( ch == '\\' ) { /* more info */ |
| 255 | ch = getc(bpf); /* maybe on next line */ |
| 256 | if (ch == '\n') continue; /* read it in next loop */ |
| 257 | ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */ |
| 258 | } else ungetc(ch, bpf); /* but who know what a `\` is */ |
| 259 | } /* needed for. */ |
| 260 | } else break; /* a commented rest-of-line */ |
| 261 | } |
| 262 | } |
| 263 | if (fclose(bpf)) { warnx("could not close %s", bootpfile); } |
| 264 | if ( res == -1) buffer[0] = '\0'; /* host found, file not */ |
| 265 | return(match); |
| 266 | } |
| 267 | |
| 268 | /* checkhost puts the hostname found in the database file in |
| 269 | the hostname-variable and returns 1, if askname is a valid |
| 270 | name for a host in the database */ |
| 271 | |
| 272 | int |
| 273 | checkhost(char *askname, char *hostname, int len) |
| 274 | { |
| 275 | int ch, pch; |
| 276 | FILE *bpf; |
| 277 | int res = 0; |
| 278 | static char *result; |
| 279 | int resultlen; |
| 280 | static char *yp_domain; |
| 281 | |
| 282 | /* struct hostent *cmp_he;*/ |
| 283 | |
| 284 | bpf = fopen(bootpfile, "r"); |
| 285 | if ( ! bpf ) |
| 286 | errx(1, "no %s", bootpfile); |
| 287 | |
| 288 | /* XXX there is no way in ISO C to specify the maximal length for a |
| 289 | conversion in a variable way */ |
| 290 | while ( fscanf(bpf, "%254s", hostname) > 0 ) { |
| 291 | if ( *hostname != '#' ) { /* comment */ |
| 292 | if ( ! strcmp(hostname, askname) ) { |
| 293 | /* return true for match of hostname */ |
| 294 | res = 1; |
| 295 | break; |
| 296 | } else { |
| 297 | /* check the alias list */ |
| 298 | he = NULL; |
| 299 | he = gethostbyname(hostname); |
| 300 | if (he && !strcmp(askname, he->h_name)) { |
| 301 | res = 1; |
| 302 | break; |
| 303 | } |
| 304 | } |
| 305 | } |
| 306 | if (*hostname == '+' ) { /* NIS */ |
| 307 | if (yp_get_default_domain(&yp_domain)) { |
| 308 | if (debug) warn("NIS"); |
| 309 | return(0); |
| 310 | } |
| 311 | if (!yp_match(yp_domain, "bootparams", askname, strlen(askname), |
| 312 | &result, &resultlen)) { |
| 313 | /* return true for match of hostname */ |
| 314 | he = NULL; |
| 315 | he = gethostbyname(askname); |
| 316 | if (he && !strcmp(askname, he->h_name)) { |
| 317 | res = 1; |
| 318 | snprintf(hostname, len, "%s", he->h_name); |
| 319 | } |
| 320 | } |
| 321 | if (fclose(bpf)) |
| 322 | warnx("could not close %s", bootpfile); |
| 323 | return(res); |
| 324 | } |
| 325 | /* skip to next entry */ |
| 326 | pch = ch = getc(bpf); |
| 327 | while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) { |
| 328 | pch = ch; ch = getc(bpf); |
| 329 | } |
| 330 | } |
| 331 | if (fclose(bpf)) { warnx("could not close %s", bootpfile); } |
| 332 | return(res); |
| 333 | } |