/* * for some weird reason T2queryall() returns share names * in lower case so we have to do an extra test against * our share table to validate filename case. * * on top of this here (snell & Wilcox) most of our * redirections point to a share of the same name, * but some do not, thus the tail of the filename * returned by T2queryall() is not the same as * the name we wanted. * * We work around this by not validating the names * or files which resolve to share names as they must * be correct, having been enforced in the dfs layer. */ static int validfile(char *found, char *want, char *winpath, Share *sp) { char *share; if(strcmp(want, "..") == 0) return 1; if(strcmp(winpath, "/") == 0){ share = trimshare(sp->name); if(cistrcmp(want, share) == 0) return strcmp(want, share) == 0; /* * OK, a DFS redirection points us from a directory XXX * to a share named YYY. There is no case checking we can * do so we allow either case - it's all we can do. */ return 1; } if(cistrcmp(found, want) != 0) return 0; if(!Checkcase) return 1; if(strcmp(found, want) == 0) return 1; return 0; }
void msgheadline(Biobuf *bin, int n, Biobuf *bout) { char *p, *q; char *date; char *from; char *subject; date = nil; from = nil; subject = nil; while(p = Brdline(bin, '\n')){ p[Blinelen(bin)-1] = '\0'; if((q = strchr(p, ':')) == nil) continue; *q++ = '\0'; if(cistrcmp(p, "from")==0) from = fixfrom(skipwhite(q)); else if(cistrcmp(p, "subject")==0) subject = estrdup(skipwhite(q)); else if(cistrcmp(p, "date")==0) date = fixdate(skipwhite(q)); } Bprint(bout, "%d/\t%s", n, from ? from : ""); if(date) Bprint(bout, "\t%s", date); if(subject) Bprint(bout, "\n\t%s", subject); Bprint(bout, "\n"); free(date); free(from); free(subject); }
/* * true if a name is in our area */ Area* inmyarea(char *name) { int len; Area *s, *d; len = strlen(name); for(s = owned; s; s = s->next){ if(s->len > len) continue; if(cistrcmp(s->soarr->owner->name, name + len - s->len) == 0) if(len == s->len || name[len - s->len - 1] == '.') break; } if(s == 0) return 0; for(d = delegated; d; d = d->next){ if(d->len > len) continue; if(cistrcmp(d->soarr->owner->name, name + len - d->len) == 0) if(len == d->len || name[len - d->len - 1] == '.') return 0; } return s; }
int hcheckcontent(HContent *me, HContent *oks, char *list, int size) { HContent *ok; if(oks == nil || me == nil) return 1; for(ok = oks; ok != nil; ok = ok->next){ if((cistrcmp(ok->generic, me->generic) == 0 || strcmp(ok->generic, "*") == 0) && (me->specific == nil || cistrcmp(ok->specific, me->specific) == 0 || strcmp(ok->specific, "*") == 0)){ if(ok->mxb > 0 && size > ok->mxb) return 0; return 1; } } USED(list); if(0){ fprint(2, "list: %s/%s not found\n", me->generic, me->specific); for(; oks != nil; oks = oks->next){ if(oks->specific) fprint(2, "\t%s/%s\n", oks->generic, oks->specific); else fprint(2, "\t%s\n", oks->generic); } } return 0; }
/* * genaudiovolwrite modifies the buffer that gets passed to it. this * is ok as long as it is called from inside Audio.volwrite() because * audiowrite() copies the data to Audiochan.buf[] and inserts a * terminating \0 byte before calling Audio.volwrite(). */ long genaudiovolwrite(Audio *adev, void *a, long n, vlong, Volume *vol, int (*volset)(Audio *, int, int *), ulong caps) { int ntok, i, j, v[2]; char *p, *e, *x, *tok[4]; p = a; e = p + n; for(;p < e; p = x){ if(x = strchr(p, '\n')) *x++ = 0; else x = e; ntok = tokenize(p, tok, 4); if(ntok <= 0) continue; if(ntok == 1){ tok[1] = tok[0]; tok[0] = "master"; ntok = 2; } for(i = 0; vol[i].name != 0; i++){ if(vol[i].cap && (vol[i].cap & caps) == 0) continue; if(cistrcmp(vol[i].name, tok[0])) continue; if((ntok>2) && (!cistrcmp(tok[1], "out") || !cistrcmp(tok[1], "in"))) memmove(tok+1, tok+2, --ntok); v[0] = 0; v[1] = 0; if(ntok > 1) v[0] = v[1] = atoi(tok[1]); if(ntok > 2) v[1] = atoi(tok[2]); if(vol[i].type == Absolute) (*volset)(adev, i, v); else { for(j=0; j<2; j++){ v[j] = (50+(v[j]*vol[i].range))/100; if(v[j] < 0) v[j] = 0; if(v[j] > vol[i].range) v[j] = vol[i].range; } (*volset)(adev, i, v); } break; } if(vol[i].name == nil) error(Evolume); } return n; }
static int incountries(char *s, Country *cp) { for(; cp->code != 0; cp++) if(cistrcmp(s, cp->code) == 0 || cistrcmp(s, cp->name) == 0) return 1; return 0; }
SmbService * smbservicefind(SmbSession *s, char *uncpath, char *servicetype, uint8_t *errclassp, uint16_t *errorp) { char *p, *q; if ((uncpath[0] == '/' && uncpath[1] == '/') || (uncpath[0] == '\\' && uncpath[1] == '\\')) { /* check that the server name matches mine */ p = uncpath + 2; q = strchr(p, uncpath[0]); if (q == nil) goto bad; *q++ = 0; // if (cistrcmp(p, smbglobals.serverinfo.name) != 0) // goto bad; } else q = uncpath + 1; if (strcmp(servicetype, "?????") == 0 && strcmp(q, "IPC$") == 0) return &ipc; if ((strcmp(servicetype, "?????") == 0 || strcmp(servicetype, "A:") == 0)) { SmbService *serv; if (cistrcmp(q, local.name) == 0) return &local; /* try the session specific list */ for (serv = s->serv; serv; serv = serv->next) if (cistrcmp(q, serv->name) == 0) return serv; /* exec "9fs q" in case it invents /n/q */ for (p = q; *p; p++) if (*p >= 'A' && *p <= 'Z') *p = tolower(*p); if (run9fs(q) >= 0) { serv = smbemallocz(sizeof(*serv), 1); serv->name = smbestrdup(q); serv->type = smbestrdup("A:"); serv->stype = STYPE_DISKTREE; smbstringprint(&serv->remark, "9fs %s", q); smbstringprint(&serv->path, "/n/%s", q); serv->next = s->serv; s->serv = serv; return serv; } } bad: *errclassp = ERRDOS; *errorp = ERRbadpath; return nil; }
static int casestrcmp(int isplan9, char *a, char *b) { if(isplan9) return strcmp(a, b); return cistrcmp(a, b); }
int find (char *word, keytab_entry keytab[], int numkeys) /* Find looks up a word in a keyword table. It uses binary search and is insensitive to case. Parameters: word: pointer to the word to be looked up keytab: pointer to the array of keywords numkeys: length of the keyword table Return value: Normal token number associated with the keyword Otherwise -1 if the keyword cannot be found */ { int high,low,mid,place ; low = 0 ; high = numkeys-1 ; while (low <= high) { mid = (high+low)/2 ; place = cistrcmp(word,keytab[mid].keyword) ; switch (place) { case -1: high = mid-1 ; break ; case 0: return (keytab[mid].token) ; case 1: low = mid+1 ; break ; } } return (-1) ; }
static SmbProcessResult netserverenum2(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata) { uint16_t level, rbl; char *domain; uint32_t servertype; SmbProcessResult pr; SmbServerInfo *si[3]; SmbServerInfo domainsi; int entries; /* WrLehDz * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ENTCOUNT pcEntriesRead, ushort *pcTotalAvail, * ulong fServerType, char *pszDomain */ if (!smbbuffergets(inparam, &level) || !smbbuffergets(inparam, &rbl) || !smbbuffergetl(inparam, &servertype) || !smbbuffergetstr(inparam, 0, &domain)) { fmtfail: pr = SmbProcessResultFormat; goto done; } smblogprintif(smbglobals.log.rap2, "netserverenum2(%lud, %lud, 0x%.8lux, %s)\n", level, smbbufferwritespace(outdata), servertype, domain); if (level > 1) goto fmtfail; if (servertype == 0xffffffff) servertype &= ~(SV_TYPE_DOMAIN_ENUM | SV_TYPE_LOCAL_LIST_ONLY); if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0 && (servertype & SV_TYPE_DOMAIN_ENUM) == 0) servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM); entries = 0; if ((servertype & SV_TYPE_SERVER) != 0 && (domain[0] == 0 || cistrcmp(domain, smbglobals.primarydomain) == 0)) { si[entries++] = &smbglobals.serverinfo; } if ((servertype & SV_TYPE_DOMAIN_ENUM) != 0) { /* there's only one that I know about */ memset(&domainsi, 0, sizeof(domainsi)); domainsi.name = smbglobals.primarydomain; domainsi.stype = SV_TYPE_DOMAIN_ENUM; si[entries++] = &domainsi; } si[entries] = 0; pr = thingfill(outparam, outdata, &serverinfo, level, si); done: free(domain); return pr; }
static int indomains(char *s, char **dp) { for(; *dp != nil; dp++) if(cistrcmp(s, *dp) == 0) return 1; return 0; }
int smbslut(SmbSlut *s, char *pat) { while (s->name) { if (cistrcmp(s->name, pat) == 0) return s->val; s++; } return -1; }
static int dateindex(char *d, char **tab, int n) { int i; for(i = 0; i < n; i++) if(cistrcmp(d, tab[i]) == 0) return i; return -1; }
static int getmon(char *s) { int i; for(i=0; i<nelem(months); i++) if(cistrcmp(months[i], s) == 0) return i; return -1; }
char* getconf(char *name) { int i; for(i = 0; i < nconf; i++) if(cistrcmp(confname[i], name) == 0) return confval[i]; return 0; }
int whichheader(char *h) { int i; for(i=0; headers[i]!=nil; i++) if(cistrcmp(h, headers[i]) == 0) return i; return -1; }
static int findconf(char *name) { int i; for(i = 0; i < nconf; i++) if(cistrcmp(confname[i], name) == 0) return i; return -1; }
char* getconf(char *name) { int i; for(i = 0; i < nconf; i++) if(cistrcmp(name, plan9ini[i].name) == 0) return plan9ini[i].val; return nil; }
static int s**t(S**t *s, char *pat) { while (s->name) { if (cistrcmp(s->name, pat) == 0) return s->val; s++; } Bprint(&bout, "%s unrecognised\n", pat); return -1; }
char * getconf(char *name) { int n; for(n = 0; n < nconf; n++) if(cistrcmp(confname[n], name) == 0) { return confval[n]; } return 0; }
/* * copy the contents of one mailbox to another * either truncates or removes the source box if it succeeds. */ int copyBox(char *from, char *to, int doremove) { MbLock *ml; char *fimp, *timp; int ffd, tfd, ok; if(cistrcmp(from, "inbox") == 0) from = "mbox"; ml = mbLock(); if(ml == nil) return 0; ffd = openLocked(mboxDir, from, OREAD); if(ffd < 0){ mbUnlock(ml); return 0; } tfd = createBox(to, 0); if(tfd < 0){ mbUnlock(ml); close(ffd); return 0; } ok = copyData(ffd, tfd, ml); close(ffd); close(tfd); if(!ok){ mbUnlock(ml); return 0; } fimp = impName(from); timp = impName(to); if(fimp != nil && timp != nil){ ffd = cdOpen(mboxDir, fimp, OREAD); if(ffd >= 0){ tfd = cdCreate(mboxDir, timp, OWRITE, 0664); if(tfd >= 0){ copyData(ffd, tfd, ml); close(tfd); } close(ffd); } } cdRemove(mboxDir, fimp); if(doremove) cdRemove(mboxDir, from); else close(cdOpen(mboxDir, from, OWRITE|OTRUNC)); mbUnlock(ml); return 1; }
static void mga4xxblank(VGAscr *scr, int blank) { char *cp; uchar *mga; uchar seq1, crtcext1; /* blank = 0 -> turn screen on */ /* blank = 1 -> turn screen off */ if(scr->mmio == 0) return; mga = (uchar*)scr->mmio; if(blank == 0){ seq1 = 0x00; crtcext1 = 0x00; } else { seq1 = 0x20; crtcext1 = 0x10; /* Default value ... : standby */ cp = getconf("*dpms"); if(cp){ if(cistrcmp(cp, "standby") == 0) crtcext1 = 0x10; else if(cistrcmp(cp, "suspend") == 0) crtcext1 = 0x20; else if(cistrcmp(cp, "off") == 0) crtcext1 = 0x30; } } *(mga + 0x1fc4) = 1; seq1 |= *(mga + 0x1fc5) & ~0x20; *(mga + 0x1fc5) = seq1; *(mga + 0x1fde) = 1; crtcext1 |= *(mga + 0x1fdf) & ~0x30; *(mga + 0x1fdf) = crtcext1; }
int main(void) { /* strings that are the same, considered case-insensitively */ static char s1[] = "`1234567890-=!\"$%^&*(" ")_+qwertyuiopasdfghjklzxcvbnm[]{};'#:@~,./<>? \t\n\r"; static char s2[] = "`1234567890-=!\"$%^&*(" ")_+QWERTYUIOPASDFGHJKLZXCVBNM[]{};'#:@~,./<>? \t\n\r"; /* string that is almost the same but actually different */ static char s3[] = "`1234567890-=!\"$%^&*(" ")_+QWERTYUIOPASDFGHJKLZXCVBNN[]{};'#:@~,./<>? \t\n\r"; lvb_initialize(); lvb_assert(cistrcmp(s1, s1) == 0); lvb_assert(cistrcmp(s3 + 5, s3) != 0); lvb_assert(cistrcmp(s1, s2) == 0); lvb_assert(cistrcmp(s2, s3) != 0); printf("test passed\n"); return 0; }
int mapshare(char *path, Share **osp) { int i; Share *sp; Dfscache *cp; char *s, *try; char *tail[] = { "", "$" }; if((cp = lookup(path, nil)) == nil) return 0; for(sp = Shares; sp < Shares+Nshares; sp++){ s = trimshare(sp->name); if(cistrcmp(cp->share, s) != 0) continue; if(Checkcase && strcmp(cp->share, s) != 0) continue; if(Debug && strstr(Debug, "dfs") != nil) print("mapshare, already connected, src=%q => dst=%q\n", path, sp->name); *osp = sp; return 0; } /* * Try to autoconnect to share if it is not known. Note even if you * didn't specify any shares and let the system autoconnect you may * not already have the share you need as RAP (which we use) throws * away names > 12 chars long. If we where to use RPC then this block * of code would be less important, though it would still be useful * to catch Shares added since cifs(1) was started. */ sp = Shares + Nshares; for(i = 0; i < 2; i++){ try = smprint("%s%s", cp->share, tail[i]); if(CIFStreeconnect(Sess, Sess->cname, try, sp) == 0){ sp->name = try; *osp = sp; Nshares++; if(Debug && strstr(Debug, "dfs") != nil) print("mapshare connected, src=%q dst=%q\n", path, cp->share); return 0; } free(try); } if(Debug && strstr(Debug, "dfs") != nil) print("mapshare failed src=%s\n", path); werrstr("not found"); return -1; }
char* impName(char *name) { char *s; int n; if(cistrcmp(name, "inbox") == 0) name = "mbox"; n = strlen(name) + STRLEN(".imp") + 1; s = binalloc(&parseBin, n, 0); if(s == nil) return nil; snprint(s, n, "%s.imp", name); return s; }
void consinit(char* name, char* speed) { int baud, port; if(name == nil || cistrcmp(name, "cga") == 0) return; port = strtoul(name, 0, 0); if(port < 0 || port > 1) return; if(speed == nil || (baud = strtoul(speed, 0, 0)) == 0) baud = 9600; qinit(&consoq); uartspecial(port, kbdchar, consputc, baud); useuart = 1; uartputs(&consoq, "\n", 1); }
static SmbProcessResult netsharegetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata) { char *netname; uint16_t level; SmbProcessResult pr; SmbService *serv; /* * zWrLh * char *pszNetName, ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail */ if (!smbbuffergetstrinline(inparam, &netname) || !smbbuffergets(inparam, &level)) { fmtfail: pr = SmbProcessResultFormat; goto done; } smblogprintif(smbglobals.log.rap2, "netsharegetinfo(%s, %lud, %lud)\n", netname, level, smbbufferwritespace(outdata)); if (level > 2) goto fmtfail; for (serv = smbservices; serv; serv = serv->next) if (cistrcmp(serv->name, netname) == 0) break; if (serv == nil) { smblogprint(-1, "netsharegetinfo: service %s unimplemented\n", netname); pr = SmbProcessResultUnimp; goto done; } pr = onethingfill(outparam, outdata, &shareinfo, level, serv); done: return pr; }
int nntpxcmdprobe(Netbuf *n) { int i; char *p; n->extended = 0; if (nntpcmd(n, "LIST EXTENSIONS", 0) < 0 || n->code != 202) return 0; while((p = Nrdline(n)) != nil) { if (strcmp(p, ".") == 0) break; for(i=0; extensions[i].s != nil; i++) if (cistrcmp(extensions[i].s, p) == 0) { n->extended |= extensions[i].n; break; } } return 0; }
void hello(String *himp, int extended) { char **mynames; char *ldot, *rdot; him = s_to_c(himp); syslog(0, "smtpd", "%s from %s as %s", extended? "ehlo": "helo", nci->rsys, him); if(rejectcheck()) return; if (strchr(him, '.') && nci && !trusted && fflag && strcmp(nci->rsys, nci->lsys) != 0){ /* * We don't care if he lies about who he is, but it is * not okay to pretend to be us. Many viruses do this, * just parroting back what we say in the greeting. */ if(strcmp(him, dom) == 0) goto Liarliar; for(mynames = sysnames_read(); mynames && *mynames; mynames++){ if(cistrcmp(*mynames, him) == 0){ Liarliar: syslog(0, "smtpd", "Hung up on %s; claimed to be %s", nci->rsys, him); if(Dflag) sleep(delaysecs()*1000); reply("554 5.7.0 Liar!\r\n"); exits("client pretended to be us"); return; } } } /* * it is unacceptable to claim any string that doesn't look like * a domain name (e.g., has at least one dot in it), but * Microsoft mail client software gets this wrong, so let trusted * (local) clients omit the dot. */ rdot = strrchr(him, '.'); if (rdot && rdot[1] == '\0') { *rdot = '\0'; /* clobber trailing dot */ rdot = strrchr(him, '.'); /* try again */ } if (!trusted && rdot == nil) goto Liarliar; /* * Reject obviously bogus domains and those reserved by RFC 2606. */ if (rdot == nil) rdot = him; else rdot++; if (!trusted && (cistrcmp(rdot, "localdomain") == 0 || cistrcmp(rdot, "localhost") == 0 || cistrcmp(rdot, "example") == 0 || cistrcmp(rdot, "invalid") == 0 || cistrcmp(rdot, "test") == 0)) goto Liarliar; /* bad top-level domain */ /* check second-level RFC 2606 domains: example\.(com|net|org) */ if (rdot != him) *--rdot = '\0'; ldot = strrchr(him, '.'); if (rdot != him) *rdot = '.'; if (ldot == nil) ldot = him; else ldot++; if (cistrcmp(ldot, "example.com") == 0 || cistrcmp(ldot, "example.net") == 0 || cistrcmp(ldot, "example.org") == 0) goto Liarliar; /* * similarly, if the claimed domain is not an address-literal, * require at least one letter, which there will be in * at least the last component (e.g., .com, .net) if it's real. * this rejects non-address-literal IP addresses, * among other bogosities. */ if (!trusted && him[0] != '[') { char *p; for (p = him; *p != '\0'; p++) if (isascii(*p) && isalpha(*p)) break; if (*p == '\0') goto Liarliar; } if(strchr(him, '.') == 0 && nci != nil && strchr(nci->rsys, '.') != nil) him = nci->rsys; if(Dflag) sleep(delaysecs()*1000); reply("250%c%s you are %s\r\n", extended ? '-' : ' ', dom, him); if (extended) { reply("250-ENHANCEDSTATUSCODES\r\n"); /* RFCs 2034 and 3463 */ if(tlscert != nil) reply("250-STARTTLS\r\n"); if (passwordinclear) reply("250 AUTH CRAM-MD5 PLAIN LOGIN\r\n"); else reply("250 AUTH CRAM-MD5\r\n"); } }
void auth(String *mech, String *resp) { char *user, *pass, *scratch = nil; AuthInfo *ai = nil; Chalstate *chs = nil; String *s_resp1_64 = nil, *s_resp2_64 = nil, *s_resp1 = nil; String *s_resp2 = nil; if (rejectcheck()) goto bomb_out; syslog(0, "smtpd", "auth(%s, %s) from %s", s_to_c(mech), "(protected)", him); if (authenticated) { bad_sequence: rejectcount++; reply("503 5.5.2 Bad sequence of commands\r\n"); goto bomb_out; } if (cistrcmp(s_to_c(mech), "plain") == 0) { if (!passwordinclear) { rejectcount++; reply("538 5.7.1 Encryption required for requested " "authentication mechanism\r\n"); goto bomb_out; } s_resp1_64 = resp; if (s_resp1_64 == nil) { reply("334 \r\n"); s_resp1_64 = s_new(); if (getcrnl(s_resp1_64, &bin) <= 0) goto bad_sequence; } s_resp1 = s_dec64(s_resp1_64); if (s_resp1 == nil) { rejectcount++; reply("501 5.5.4 Cannot decode base64\r\n"); goto bomb_out; } memset(s_to_c(s_resp1_64), 'X', s_len(s_resp1_64)); user = s_to_c(s_resp1) + strlen(s_to_c(s_resp1)) + 1; pass = user + strlen(user) + 1; ai = auth_userpasswd(user, pass); authenticated = ai != nil; memset(pass, 'X', strlen(pass)); goto windup; } else if (cistrcmp(s_to_c(mech), "login") == 0) { if (!passwordinclear) { rejectcount++; reply("538 5.7.1 Encryption required for requested " "authentication mechanism\r\n"); goto bomb_out; } if (resp == nil) { reply("334 VXNlcm5hbWU6\r\n"); s_resp1_64 = s_new(); if (getcrnl(s_resp1_64, &bin) <= 0) goto bad_sequence; } reply("334 UGFzc3dvcmQ6\r\n"); s_resp2_64 = s_new(); if (getcrnl(s_resp2_64, &bin) <= 0) goto bad_sequence; s_resp1 = s_dec64(s_resp1_64); s_resp2 = s_dec64(s_resp2_64); memset(s_to_c(s_resp2_64), 'X', s_len(s_resp2_64)); if (s_resp1 == nil || s_resp2 == nil) { rejectcount++; reply("501 5.5.4 Cannot decode base64\r\n"); goto bomb_out; } ai = auth_userpasswd(s_to_c(s_resp1), s_to_c(s_resp2)); authenticated = ai != nil; memset(s_to_c(s_resp2), 'X', s_len(s_resp2)); windup: if (authenticated) { /* if you authenticated, we trust you despite your IP */ trusted = 1; reply("235 2.0.0 Authentication successful\r\n"); } else { rejectcount++; reply("535 5.7.1 Authentication failed\r\n"); syslog(0, "smtpd", "authentication failed: %r"); } goto bomb_out; } else if (cistrcmp(s_to_c(mech), "cram-md5") == 0) { int chal64n; char *resp, *t; chs = auth_challenge("proto=cram role=server"); if (chs == nil) { rejectcount++; reply("501 5.7.5 Couldn't get CRAM-MD5 challenge\r\n"); goto bomb_out; } scratch = malloc(chs->nchal * 2 + 1); chal64n = enc64(scratch, chs->nchal * 2, (uchar *)chs->chal, chs->nchal); scratch[chal64n] = 0; reply("334 %s\r\n", scratch); s_resp1_64 = s_new(); if (getcrnl(s_resp1_64, &bin) <= 0) goto bad_sequence; s_resp1 = s_dec64(s_resp1_64); if (s_resp1 == nil) { rejectcount++; reply("501 5.5.4 Cannot decode base64\r\n"); goto bomb_out; } /* should be of form <user><space><response> */ resp = s_to_c(s_resp1); t = strchr(resp, ' '); if (t == nil) { rejectcount++; reply("501 5.5.4 Poorly formed CRAM-MD5 response\r\n"); goto bomb_out; } *t++ = 0; chs->user = resp; chs->resp = t; chs->nresp = strlen(t); ai = auth_response(chs); authenticated = ai != nil; goto windup; } rejectcount++; reply("501 5.5.1 Unrecognised authentication type %s\r\n", s_to_c(mech)); bomb_out: if (ai) auth_freeAI(ai); if (chs) auth_freechal(chs); if (scratch) free(scratch); if (s_resp1) s_free(s_resp1); if (s_resp2) s_free(s_resp2); if (s_resp1_64) s_free(s_resp1_64); if (s_resp2_64) s_free(s_resp2_64); }