Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
Please login to access the resource
SUSE:SLE-15:Update
sendmail.32316
sendmail-8.15.2-smtpmode.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File sendmail-8.15.2-smtpmode.patch of Package sendmail.32316
--- doc/op/op.me | 31 ++++++++++++ sendmail/collect.c | 134 +++++++++++++++++++++++++++++++++------------------- sendmail/envelope.c | 2 sendmail/main.c | 5 + sendmail/mime.c | 4 - sendmail/sendmail.h | 13 +++-- sendmail/srvrsmtp.c | 55 ++++++++++++--------- 7 files changed, 165 insertions(+), 79 deletions(-) --- doc/op/op.me +++ doc/op/op.me 2024-01-24 12:26:34.361010730 +0000 @@ -4441,6 +4441,30 @@ passive attack (e.g., PLAIN, LOGIN), unl Option `l' requires SMTP AUTH for a connection. Options 'B', 'D', 'E', and 'X' suppress SMTP VERB, DSN, ETRN, and EXPN, respectively. +Option 'o' causes the server to accept only +CR LF . CR LF +as end of an SMTP message as required by the RFCs +which is also a defense against SMTP smuggling (CVE-2023-51765). +Option 'O' allows the server to accept a single dot on a line by itself +as end of an SMTP message. +Option 'g' instructs the server to fail SMTP messages +which have a LF without a CR directly before it ("bare LF") +by dropping the session with a 421 error. +Option 'G' accepts SMTP messages which have a "bare LF". +Option 'u' instructs the server to fail SMTP messages +which have a CR without a LF directly after it ("bare CR") +by dropping the session with a 421 error. +Option 'U' accepts SMTP messages which have a "bare CR". +If needed, internal system with broken SMTP implementations +can be allowed some violations, e.g., a combination of +.(b +G U O +.)b +A command like +.(b +egrep 'Bare.*(CR|LF).*not allowed' $MAILLOG +.)b +can be used to find hosts which send bare CR/LF. .(b .ta 9n A Do not offer AUTH @@ -4454,12 +4478,19 @@ D Do not offer DSN d Offer DSN (default) E Do not offer ETRN e Offer ETRN (default) +G Accept "bare LF"s in a message +g Do not accept "bare LF"s in a message (default) L Do not require AUTH (default) l Require AUTH +O Accept a single dot on a line by itself + as end of an SMTP message +o Require CR LF . CR LF as end of an SMTP message (default) P Do not offer PIPELINING p Offer PIPELINING (default) S Do not offer STARTTLS s Offer STARTTLS (default) +U Accept "bare CR"s in a message +u Do not accept "bare CR"s in a message (default) V Do not request a client certificate v Request a client certificate (default) X Do not offer EXPN --- sendmail/collect.c +++ sendmail/collect.c 2024-01-24 11:57:28.125474171 +0000 @@ -239,10 +239,10 @@ collect_dfopen(e) ** ** Parameters: ** fp -- file to read. -** smtpmode -- if set, we are running SMTP: give an RFC821 -** style message to say we are ready to collect -** input, and never ignore a single dot to mean -** end of message. +** smtpmode -- if >= SMTPMODE_LAX we are running SMTP: +** give an RFC821 style message to say we are +** ready to collect input, and never ignore +** a single dot to mean end of message. ** hdrp -- the location to stash the header. ** e -- the current envelope. ** rsetsize -- reset e_msgsize? @@ -265,20 +265,26 @@ collect_dfopen(e) /* values for input state machine */ #define IS_NORM 0 /* middle of line */ #define IS_BOL 1 /* beginning of line */ -#define IS_DOT 2 /* read a dot at beginning of line */ +#define IS_DOT 2 /* read "." at beginning of line */ #define IS_DOTCR 3 /* read ".\r" at beginning of line */ -#define IS_CR 4 /* read a carriage return */ +#define IS_CR 4 /* read "\r" */ + +/* hack to enhance readability of debug output */ +static const char *istates[] = { "NORM", "BOL", "DOT", "DOTCR", "CR" }; +#define ISTATE istates[istate] /* values for message state machine */ #define MS_UFROM 0 /* reading Unix from line */ #define MS_HEADER 1 /* reading message header */ #define MS_BODY 2 /* reading message body */ #define MS_DISCARD 3 /* discarding rest of message */ +#define BARE_LF_MSG "Bare linefeed (LF) not allowed" +#define BARE_CR_MSG "Bare carriage return (CR) not allowed" void collect(fp, smtpmode, hdrp, e, rsetsize) SM_FILE_T *fp; - bool smtpmode; + int smtpmode; HDR **hdrp; register ENVELOPE *e; bool rsetsize; @@ -304,12 +310,19 @@ collect(fp, smtpmode, hdrp, e, rsetsize) #if _FFR_REJECT_NUL_BYTE bool hasNUL; /* has at least one NUL input byte */ #endif /* _FFR_REJECT_NUL_BYTE */ + bool bare_lf = false; + bool bare_cr = false; + +#define SMTPMODE (smtpmode >= SMTPMODE_LAX) +#define SMTPMODE_STRICT ((smtpmode & SMTPMODE_CRLF) != 0) +#define SMTPMODE_BARE_LF_421 ((smtpmode & SMTPMODE_LF_421) != 0) +#define SMTPMODE_BARE_CR_421 ((smtpmode & SMTPMODE_CR_421) != 0) df = NULL; - ignrdot = smtpmode ? false : IgnrDot; + ignrdot = SMTPMODE ? false : IgnrDot; /* timeout for I/O functions is in milliseconds */ - dbto = smtpmode ? ((int) TimeOuts.to_datablock * 1000) + dbto = SMTPMODE ? ((int) TimeOuts.to_datablock * 1000) : SM_TIME_FOREVER; sm_io_setinfo(fp, SM_IO_WHAT_TIMEOUT, &dbto); old_rd_tmo = set_tls_rd_tmo(TimeOuts.to_datablock); @@ -332,15 +345,15 @@ collect(fp, smtpmode, hdrp, e, rsetsize) ** Tell ARPANET to go ahead. */ - if (smtpmode) - message("354 Enter mail, end with \".\" on a line by itself"); + if (SMTPMODE) + message("354 End data with <CR><LF>.<CR><LF>"); /* simulate an I/O timeout when used as sink */ if (tTd(83, 101)) sleep(319); if (tTd(30, 2)) - sm_dprintf("collect\n"); + sm_dprintf("collect, smtpmode=%#x\n", smtpmode); /* ** Read the message. @@ -356,7 +369,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize) for (;;) { if (tTd(30, 35)) - sm_dprintf("top, istate=%d, mstate=%d\n", istate, + sm_dprintf("top, istate=%s, mstate=%d\n", ISTATE, mstate); for (;;) { @@ -377,7 +390,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize) /* timeout? */ if (c == SM_IO_EOF && errno == EAGAIN - && smtpmode) + && SMTPMODE) { /* ** Override e_message in @@ -415,15 +428,36 @@ collect(fp, smtpmode, hdrp, e, rsetsize) hasNUL = true; #endif /* _FFR_REJECT_NUL_BYTE */ if (c == SM_IO_EOF) - goto readerr; + goto readdone; if (SevenBitInput) c &= 0x7f; else HasEightBits |= bitset(0x80, c); } if (tTd(30, 94)) - sm_dprintf("istate=%d, c=%c (0x%x)\n", - istate, (char) c, c); + sm_dprintf("istate=%s, c=%c (0x%x)\n", + ISTATE, (char) c, c); + if ('\n' == c && !bare_lf && SMTPMODE && + !(IS_CR == istate || IS_DOTCR == istate)) + { + bare_lf = true; + if (SMTPMODE_BARE_LF_421) + { + inputerr = true; + goto readabort; + } + } + if (!bare_cr && SMTPMODE && + (IS_CR == istate || IS_DOTCR == istate) + && '\n' != c) + { + bare_cr = true; + if (SMTPMODE_BARE_CR_421) + { + inputerr = true; + goto readabort; + } + } switch (istate) { case IS_BOL: @@ -435,11 +469,9 @@ collect(fp, smtpmode, hdrp, e, rsetsize) break; case IS_DOT: - if (c == '\n' && !ignrdot && - !bitset(EF_NL_NOT_EOL, e->e_flags)) - goto readerr; - else if (c == '\r' && - !bitset(EF_CRLF_NOT_EOL, e->e_flags)) + if (c == '\n' && !ignrdot && !SMTPMODE_STRICT) + goto readdone; + else if (c == '\r') { istate = IS_DOTCR; continue; @@ -460,7 +492,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize) case IS_DOTCR: if (c == '\n' && !ignrdot) - goto readerr; + goto readdone; else { /* push back the ".\rx" */ @@ -494,13 +526,12 @@ collect(fp, smtpmode, hdrp, e, rsetsize) goto bufferchar; } - if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) + if (c == '\r') { istate = IS_CR; continue; } - else if (c == '\n' && !bitset(EF_NL_NOT_EOL, - e->e_flags)) + else if (c == '\n' && !SMTPMODE_STRICT) istate = IS_BOL; else istate = IS_NORM; @@ -593,8 +624,8 @@ bufferchar: nextstate: if (tTd(30, 35)) - sm_dprintf("nextstate, istate=%d, mstate=%d, line=\"%s\"\n", - istate, mstate, buf); + sm_dprintf("nextstate, istate=%s, mstate=%d, line=\"%s\"\n", + ISTATE, mstate, buf); switch (mstate) { case MS_UFROM: @@ -625,7 +656,7 @@ nextstate: /* timeout? */ if (c == SM_IO_EOF && errno == EAGAIN - && smtpmode) + && SMTPMODE) { /* ** Override e_message in @@ -674,7 +705,7 @@ nextstate: sm_dprintf("EOH\n"); if (headeronly) - goto readerr; + goto readdone; df = collect_eoh(e, numhdrs, hdrslen); if (df == NULL) @@ -683,10 +714,8 @@ nextstate: bp = buf; /* toss blank line */ - if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && - bp[0] == '\r' && bp[1] == '\n') || - (!bitset(EF_NL_NOT_EOL, e->e_flags) && - bp[0] == '\n')) + if ((bp[0] == '\r' && bp[1] == '\n') || + (bp[0] == '\n')) { break; } @@ -703,8 +732,8 @@ nextstate: bp = buf; } -readerr: - if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp)) +readdone: + if ((sm_io_eof(fp) && SMTPMODE) || sm_io_error(fp)) { const char *errmsg; @@ -744,7 +773,7 @@ readerr: } else if (SuperSafe == SAFE_NO || SuperSafe == SAFE_INTERACTIVE || - (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode)) + (SuperSafe == SAFE_REALLY_POSTMILTER && SMTPMODE)) { /* skip next few clauses */ /* EMPTY */ @@ -821,21 +850,26 @@ readerr: problem = "unexpected close"; else if (sm_io_error(fp)) problem = "I/O error"; + else if (bare_lf) + problem = "bare LF"; + else if (bare_cr) + problem = "bare CR"; else problem = "read timeout"; - if (LogLevel > 0 && sm_io_eof(fp)) + +#define CONN_ERR_TXT "collect: %s on connection from %s, from=%s%s%s" +#define CONN_ERR_CODE "421 4.4.1 " +#define CONN_ERR_BARE bare_lf ? BARE_LF_MSG : (bare_cr ? BARE_CR_MSG : "") +#define CONN_ERR_ARGS problem, host, shortenstring(e->e_from.q_paddr, MAXSHORTSTR), (bare_lf || bare_cr) ? ", info=" : "", CONN_ERR_BARE + if (LogLevel > 0 && (sm_io_eof(fp) || bare_lf || bare_cr)) sm_syslog(LOG_NOTICE, e->e_id, - "collect: %s on connection from %.100s, sender=%s", - problem, host, - shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); - if (sm_io_eof(fp)) - usrerr("421 4.4.1 collect: %s on connection from %s, from=%s", - problem, host, - shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); + CONN_ERR_TXT, CONN_ERR_ARGS); + if (bare_lf || bare_cr) + usrerr(CONN_ERR_CODE "%s", CONN_ERR_BARE); + else if (sm_io_eof(fp)) + usrerr(CONN_ERR_CODE CONN_ERR_TXT, CONN_ERR_ARGS); else - syserr("421 4.4.1 collect: %s on connection from %s, from=%s", - problem, host, - shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); + syserr(CONN_ERR_CODE CONN_ERR_TXT, CONN_ERR_ARGS); flush_errors(true); /* don't return an error indication */ @@ -866,6 +900,10 @@ readerr: logsender(e, e->e_msgid); e->e_flags &= ~EF_LOGSENDER; } + if (bare_lf && LogLevel > 8) + sm_syslog(LOG_NOTICE, e->e_id, BARE_LF_MSG); + if (bare_cr && LogLevel > 8) + sm_syslog(LOG_NOTICE, e->e_id, BARE_CR_MSG); /* check for message too large */ if (bitset(EF_TOOBIG, e->e_flags)) --- sendmail/envelope.c +++ sendmail/envelope.c 2024-01-24 08:40:15.186162779 +0000 @@ -1271,8 +1271,6 @@ static struct eflags EnvelopeFlags[] = { "LOGSENDER", EF_LOGSENDER }, { "NORECEIPT", EF_NORECEIPT }, { "HAS8BIT", EF_HAS8BIT }, - { "NL_NOT_EOL", EF_NL_NOT_EOL }, - { "CRLF_NOT_EOL", EF_CRLF_NOT_EOL }, { "RET_PARAM", EF_RET_PARAM }, { "HAS_DF", EF_HAS_DF }, { "IS_MIME", EF_IS_MIME }, --- sendmail/main.c +++ sendmail/main.c 2024-01-18 14:01:08.494154339 +0000 @@ -2790,7 +2790,8 @@ main(argc, argv, envp) /* collect body for UUCP return */ if (OpMode != MD_VERIFY) - collect(InChannel, false, NULL, &MainEnvelope, true); + collect(InChannel, SMTPMODE_NO, NULL, &MainEnvelope, + true); finis(true, true, EX_USAGE); /* NOTREACHED */ } @@ -2850,7 +2851,7 @@ main(argc, argv, envp) MainEnvelope.e_flags &= ~EF_FATALERRS; Errors = 0; buffer_errors(); - collect(InChannel, false, NULL, &MainEnvelope, true); + collect(InChannel, SMTPMODE_NO, NULL, &MainEnvelope, true); /* header checks failed */ if (Errors > 0) --- sendmail/mime.c +++ sendmail/mime.c 2024-01-18 14:01:08.494154339 +0000 @@ -346,7 +346,7 @@ mime8to7(mci, header, e, boundaries, fla goto writeerr; if (tTd(43, 35)) sm_dprintf(" ...%s\n", buf); - collect(e->e_dfp, false, &hdr, e, false); + collect(e->e_dfp, SMTPMODE_NO, &hdr, e, false); if (tTd(43, 101)) putline("+++after collect", mci); if (!putheader(mci, hdr, e, flags)) @@ -408,7 +408,7 @@ mime8to7(mci, header, e, boundaries, fla goto writeerr; mci->mci_flags |= MCIF_INMIME; - collect(e->e_dfp, false, &hdr, e, false); + collect(e->e_dfp, SMTPMODE_NO, &hdr, e, false); if (tTd(43, 101)) putline("+++after collect", mci); if (!putheader(mci, hdr, e, flags)) --- sendmail/sendmail.h +++ sendmail/sendmail.h 2024-01-24 08:41:39.060584463 +0000 @@ -1017,8 +1017,8 @@ struct envelope #define EF_LOGSENDER 0x00008000L /* need to log the sender */ #define EF_NORECEIPT 0x00010000L /* suppress all return-receipts */ #define EF_HAS8BIT 0x00020000L /* at least one 8-bit char in body */ -#define EF_NL_NOT_EOL 0x00040000L /* don't accept raw NL as EOLine */ -#define EF_CRLF_NOT_EOL 0x00080000L /* don't accept CR-LF as EOLine */ +/* was: #define EF_NL_NOT_EOL 0x00040000L * don't accept raw NL as EOLine */ +/* was: #define EF_CRLF_NOT_EOL 0x00080000L * don't accept CR-LF as EOLine */ #define EF_RET_PARAM 0x00100000L /* RCPT command had RET argument */ #define EF_HAS_DF 0x00200000L /* set when data file is instantiated */ #define EF_IS_MIME 0x00400000L /* really is a MIME message */ @@ -2681,7 +2681,7 @@ extern void cleanup_shm __P((bool)); #endif /* SM_CONF_SHM */ extern void close_sendmail_pid __P((void)); extern void clrdaemon __P((void)); -extern void collect __P((SM_FILE_T *, bool, HDR **, ENVELOPE *, bool)); +extern void collect __P((SM_FILE_T *, int, HDR **, ENVELOPE *, bool)); extern bool connection_rate_check __P((SOCKADDR *, ENVELOPE *)); extern time_t convtime __P((char *, int)); extern char **copyplist __P((char **, bool, SM_RPOOL_T *)); @@ -2864,6 +2864,13 @@ extern bool xtextok __P((char *)); extern int xunlink __P((char *)); extern char *xuntextify __P((char *)); +#define SMTPMODE_NO 0 +#define SMTPMODE_LAX 0x01 +#define SMTPMODE_CRLF 0x02 /* CRLF.CRLF required for EOM */ +#define SMTPMODE_LF_421 0x04 /* no bare LF - drop connection */ +#define SMTPMODE_CR_421 0x08 /* no bare CR - drop connection */ + + #if _FFR_RCPTFLAGS extern bool newmodmailer __P((ADDRESS *, int)); #endif --- sendmail/srvrsmtp.c +++ sendmail/srvrsmtp.c 2024-01-24 12:06:37.619288193 +0000 @@ -47,26 +47,29 @@ static bool NotFirstDelivery = false; #endif /* _FFR_DM_ONE */ /* server features */ -#define SRV_NONE 0x0000 /* none... */ -#define SRV_OFFER_TLS 0x0001 /* offer STARTTLS */ -#define SRV_VRFY_CLT 0x0002 /* request a cert */ -#define SRV_OFFER_AUTH 0x0004 /* offer AUTH */ -#define SRV_OFFER_ETRN 0x0008 /* offer ETRN */ -#define SRV_OFFER_VRFY 0x0010 /* offer VRFY (not yet used) */ -#define SRV_OFFER_EXPN 0x0020 /* offer EXPN */ -#define SRV_OFFER_VERB 0x0040 /* offer VERB */ -#define SRV_OFFER_DSN 0x0080 /* offer DSN */ +#define SRV_NONE 0x00000000 /* none... */ +#define SRV_OFFER_TLS 0x00000001 /* offer STARTTLS */ +#define SRV_VRFY_CLT 0x00000002 /* request a cert */ +#define SRV_OFFER_AUTH 0x00000004 /* offer AUTH */ +#define SRV_OFFER_ETRN 0x00000008 /* offer ETRN */ +#define SRV_OFFER_VRFY 0x00000010 /* offer VRFY (not yet used) */ +#define SRV_OFFER_EXPN 0x00000020 /* offer EXPN */ +#define SRV_OFFER_VERB 0x00000040 /* offer VERB */ +#define SRV_OFFER_DSN 0x00000080 /* offer DSN */ #if PIPELINING -# define SRV_OFFER_PIPE 0x0100 /* offer PIPELINING */ +# define SRV_OFFER_PIPE 0x00000100 /* offer PIPELINING */ # if _FFR_NO_PIPE -# define SRV_NO_PIPE 0x0200 /* disable PIPELINING, sleep if used */ +# define SRV_NO_PIPE 0x00000200 /* disable PIPELINING, sleep if used */ # endif /* _FFR_NO_PIPE */ #endif /* PIPELINING */ -#define SRV_REQ_AUTH 0x0400 /* require AUTH */ -#define SRV_REQ_SEC 0x0800 /* require security - equiv to AuthOptions=p */ -#define SRV_TMP_FAIL 0x1000 /* ruleset caused a temporary failure */ +#define SRV_REQ_AUTH 0x00000400 /* require AUTH */ +#define SRV_REQ_SEC 0x00000800 /* require security - equiv to AuthOptions=p */ +#define SRV_TMP_FAIL 0x00001000 /* ruleset caused a temporary failure */ +#define SRV_REQ_CRLF 0x00010000 /* require CR LF as EOL */ +#define SRV_BARE_LF_421 0x00020000 /* bare LF - drop connection */ +#define SRV_BARE_CR_421 0x00040000 /* bare CR - drop connection */ -static unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int)); +static unsigned long srvfeatures __P((ENVELOPE *, char *, unsigned long)); #define STOP_ATTACK ((time_t) -1) static time_t checksmtpattack __P((volatile unsigned int *, unsigned int, @@ -812,7 +815,7 @@ smtp(nullserver, d_flags, e) bool saveSuprErrs; time_t tlsstart; #endif /* STARTTLS */ - volatile unsigned int features; + volatile unsigned long features; #if PIPELINING # if _FFR_NO_PIPE int np_log = 0; @@ -898,6 +901,7 @@ smtp(nullserver, d_flags, e) | (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE : SRV_VRFY_CLT) #endif /* STARTTLS */ + | SRV_REQ_CRLF | SRV_BARE_LF_421 | SRV_BARE_CR_421 ; if (nullserver == NULL) { @@ -3612,7 +3616,7 @@ smtp_data(smtp, e) ENVELOPE *ee; char *id; char *oldid; - unsigned int features; + unsigned long features; char buf[32]; SmtpPhase = "server DATA"; @@ -3744,7 +3748,11 @@ smtp_data(smtp, e) SmtpPhase = "collect"; buffer_errors(); - collect(InChannel, true, NULL, e, true); + collect(InChannel, SMTPMODE_LAX + | (bitset(SRV_BARE_LF_421, e->e_features) ? SMTPMODE_LF_421 : 0) + | (bitset(SRV_BARE_CR_421, e->e_features) ? SMTPMODE_CR_421 : 0) + | (bitset(SRV_REQ_CRLF, e->e_features) ? SMTPMODE_CRLF : 0), + NULL, e, true); /* redefine message size */ (void) sm_snprintf(buf, sizeof(buf), "%ld", PRT_NONNEGL(e->e_msgsize)); @@ -5163,7 +5171,7 @@ initsrvtls(tls_ok) static struct { char srvf_opt; - unsigned int srvf_flag; + unsigned long srvf_flag; } srv_feat_table[] = { { 'A', SRV_OFFER_AUTH }, @@ -5171,27 +5179,30 @@ static struct { 'C', SRV_REQ_SEC }, { 'D', SRV_OFFER_DSN }, { 'E', SRV_OFFER_ETRN }, + { 'G', SRV_BARE_LF_421 }, { 'L', SRV_REQ_AUTH }, #if PIPELINING # if _FFR_NO_PIPE { 'N', SRV_NO_PIPE }, # endif /* _FFR_NO_PIPE */ + { 'O', SRV_REQ_CRLF }, /* eOl */ { 'P', SRV_OFFER_PIPE }, #endif /* PIPELINING */ { 'R', SRV_VRFY_CLT }, /* same as V; not documented */ { 'S', SRV_OFFER_TLS }, /* { 'T', SRV_TMP_FAIL }, */ + { 'U', SRV_BARE_CR_421 }, { 'V', SRV_VRFY_CLT }, { 'X', SRV_OFFER_EXPN }, /* { 'Y', SRV_OFFER_VRFY }, */ { '\0', SRV_NONE } }; -static unsigned int +static unsigned long srvfeatures(e, clientname, features) ENVELOPE *e; char *clientname; - unsigned int features; + unsigned long features; { int r, i, j; char **pvp, c, opt; @@ -5225,7 +5236,7 @@ srvfeatures(e, clientname, features) { if (LogLevel > 9) sm_syslog(LOG_WARNING, e->e_id, - "srvfeatures: unknown feature %s", + "srv_features: unknown feature %s", pvp[i]); break; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor